Skip to content

Commit

Permalink
Merge pull request #226 from KisaragiEffective/feature/type-alias
Browse files Browse the repository at this point in the history
  • Loading branch information
KisaragiEffective authored Aug 30, 2023
2 parents 202a805 + ce00b02 commit cfd4596
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 16 deletions.
15 changes: 15 additions & 0 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,21 @@ var _ = _

`exit`で現在のプログラムの実行を終了します。

### `type`

`type`で型エイリアスを定義することが出来ます。

```
type VeryLargeTuple = (String, Int32, Int64, Int16, Int8, Unit, Boolean)
```

`type`で定義した型エイリアスはエイリアスする前の型と相互に交換可能です。

```
type Hello = Int32
var x: Hello = 0i32
```

## 型システム

現状型付けラムダ計算に相当する型システムを持っています。多相はありません。サブタイピングもありません。
Expand Down
4 changes: 4 additions & 0 deletions package/origlang-ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub enum Statement {
content: Comment,
},
Exit,
TypeAliasDeclaration {
new_name: Identifier,
replace_with: TypeSignature,
},
}

#[derive(Eq, PartialEq, Clone, Debug)]
Expand Down
9 changes: 9 additions & 0 deletions package/origlang-cli/src/task/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ impl Test {
Self::test_comment().expect("comment");
Self::test_exit().expect("exit");
Self::test_underscore_discard().expect("underscore_discard");
Self::test_type_alias().expect("type_alias");

Ok(())
}
Expand Down Expand Up @@ -483,6 +484,14 @@ print 1

Ok(())
}

fn test_type_alias() -> Result<(), Err> {
assert_eq!(Self::ast("type Ik = Int32\n")?.statement, [ Statement::TypeAliasDeclaration {
new_name: Identifier::new("Ik".to_string()), replace_with: TypeSignature::Simple(Identifier::new("Int32".to_string())) } ]);
assert_eq!(Self::evaluated_expressions("type Ik = Int32\n")?, []);
assert_eq!(Self::evaluated_expressions("type Ik = Int32\nvar t: Ik = 0i32\nprint t\n")?, type_boxes![0 => Int32]);
Ok(())
}
}

impl Task for Test {
Expand Down
5 changes: 3 additions & 2 deletions package/origlang-compiler/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use crate::chars::line::{LineComputation, LineComputationError};
use crate::chars::occurrence::OccurrenceSet;
use crate::lexer::token::{TemporalLexerUnwindToken, Token};

static KEYWORDS: [&str; 11] =
["var", "if", "else", "then", "exit", "true", "false", "print", "block", "end", "_"];
static KEYWORDS: [&str; 12] =
["var", "if", "else", "then", "exit", "true", "false", "print", "block", "end", "type", "_"];

trait AssociateWithPos {
fn with_pos(self, lexer: &Lexer) -> WithPosition<Self> where Self: Sized;
Expand Down Expand Up @@ -271,6 +271,7 @@ impl Lexer {
"block" => Token::KeywordBlock,
"end" => Token::KeywordEnd,
"exit" => Token::KeywordExit,
"type" => Token::KeywordType,
"_" => Token::SymUnderscore,
other => Token::Reserved {
matched: other.to_string(),
Expand Down
3 changes: 3 additions & 0 deletions package/origlang-compiler/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ pub enum Token {
},
/// `_`
SymUnderscore,
/// `type`
KeywordType,
}

impl Token {
Expand Down Expand Up @@ -148,6 +150,7 @@ impl Token {
Self::SymColon => "sym:colon",
Self::Reserved { .. } => "reserved_token",
Self::SymUnderscore => "sym:underscore",
Self::KeywordType => "keyword:type",
}
}

Expand Down
43 changes: 43 additions & 0 deletions package/origlang-compiler/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,49 @@ impl Parser {
self.lexer.next();
Statement::Exit
}
Token::KeywordType => {
self.lexer.next();
let aliased = self.lexer.next();

if let Token::Identifier { inner: aliased } = aliased.data {
let except_eq = self.lexer.next();

if let Token::SymEq = except_eq.data {

let Ok(replace_with) = self.lexer.parse_fallible(|| self.parse_type()) else {
return Err(SimpleErrorWithPos {
kind: ParserError::UnexpectedToken {
pat: TokenKind::StartOfTypeSignature,
unmatch: self.lexer.peek().data
},
position: self.lexer.peek().position
})
};

Statement::TypeAliasDeclaration {
new_name: aliased,
replace_with,
}

} else {
return Err(SimpleErrorWithPos {
kind: ParserError::UnexpectedToken {
pat: TokenKind::only(Token::SymEq),
unmatch: except_eq.data
},
position: except_eq.position
})
}
} else {
return Err(SimpleErrorWithPos {
kind: ParserError::UnexpectedToken {
pat: TokenKind::Identifier,
unmatch: aliased.data,
},
position: aliased.position,
})
}
}
x => {
return Err(SimpleErrorWithPos {
kind: ParserError::UnexpectedToken {
Expand Down
35 changes: 22 additions & 13 deletions package/origlang-compiler/src/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,15 @@ impl TryIntoTypeCheckedForm for Statement {
Self::VariableDeclaration { pattern: pattern, expression, type_annotation } => {
let checked = checker.check(expression)?;
return if let Some(type_name) = type_annotation {
if let Ok(dest) = checker.lookup(&type_name) {
if let Ok(dest) = checker.lower_type_signature_into_type(&type_name) {
match dest.is_assignable(&checked.actual_type()) {
AssignableQueryAnswer::Yes => {
match pattern {
AtomicPattern::Discard => {
Ok(TypedStatement::EvalAndForget { expression: checked })
}
AtomicPattern::Bind(identifier) => {
checker.ctx.borrow_mut().add_variable_type(identifier.clone(), checked.actual_type());
checker.ctx.borrow_mut().add_known_variable(identifier.clone(), checked.actual_type());
Ok(TypedStatement::VariableDeclaration {
identifier,
expression: checked,
Expand Down Expand Up @@ -268,7 +268,7 @@ impl TryIntoTypeCheckedForm for Statement {
Ok(TypedStatement::EvalAndForget { expression: checked })
}
AtomicPattern::Bind(identifier) => {
checker.ctx.borrow_mut().add_variable_type(identifier.clone(), checked.actual_type());
checker.ctx.borrow_mut().add_known_variable(identifier.clone(), checked.actual_type());
Ok(TypedStatement::VariableDeclaration {
identifier,
expression: checked,
Expand Down Expand Up @@ -307,7 +307,14 @@ impl TryIntoTypeCheckedForm for Statement {
Self::Comment { .. } => Ok(TypedStatement::Block {
inner_statements: vec![]
}),
Self::Exit => Ok(TypedStatement::Exit)
Self::Exit => Ok(TypedStatement::Exit),
Self::TypeAliasDeclaration { new_name, replace_with } => {
checker.ctx.borrow_mut().known_aliases.insert(new_name, checker.lower_type_signature_into_type(&replace_with).map_err(|_| TypeCheckError::UnknownType {
name: replace_with,
})?);

Ok(TypedStatement::Empty)
}
}
}
}
Expand All @@ -334,7 +341,7 @@ pub struct TypeChecker {
}

impl TypeChecker {
pub(crate) fn lookup(&self, p0: &TypeSignature) -> Result<Type, ()> {
pub(crate) fn lower_type_signature_into_type(&self, p0: &TypeSignature) -> Result<Type, ()> {
match p0 {
TypeSignature::Simple(ident) => {
match ident.as_name() {
Expand All @@ -345,13 +352,13 @@ impl TypeChecker {
"Int16" => Ok(Type::Int16),
"Int32" => Ok(Type::Int32),
"Int64" => Ok(Type::Int64),
_ => Err(())
_other => self.ctx.borrow().known_aliases.get(ident).cloned().ok_or(())
}
}
TypeSignature::Tuple(x) => {
let mut types = Vec::with_capacity(x.capacity());
for ts in x {
types.push(self.lookup(ts)?);
types.push(self.lower_type_signature_into_type(ts)?);
}

Ok(Type::tuple(types))
Expand Down Expand Up @@ -387,22 +394,24 @@ impl TypeChecker {
}

pub struct Context {
typed_variables: HashMap<Identifier, Type>,
known_typed_variables: HashMap<Identifier, Type>,
known_aliases: HashMap<Identifier, Type>,
}

impl Context {
#[must_use]
pub fn empty() -> Self {
Self {
typed_variables: HashMap::new()
known_typed_variables: HashMap::new(),
known_aliases: HashMap::new(),
}
}

fn lookup_variable_type(&self, ident: &Identifier) -> Result<Type, TypeCheckError> {
self.typed_variables.get(ident).cloned().ok_or_else(|| TypeCheckError::UndefinedIdentifier(ident.clone()))
fn lookup_variable_type(&self, variable_name: &Identifier) -> Result<Type, TypeCheckError> {
self.known_typed_variables.get(variable_name).cloned().ok_or_else(|| TypeCheckError::UndefinedIdentifier(variable_name.clone()))
}

fn add_variable_type(&mut self, ident: Identifier, tp: Type) {
self.typed_variables.insert(ident, tp);
fn add_known_variable(&mut self, variable_ident: Identifier, tp: Type) {
self.known_typed_variables.insert(variable_ident, tp);
}
}
3 changes: 2 additions & 1 deletion package/origlang-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ impl IntoVerbatimSequencedIR for TypedStatement {
TypedStatement::Exit => vec![IR0::Exit],
TypedStatement::EvalAndForget { expression } => {
vec![IR0::Normal(IR1::EvalAndForget { expression })]
}
},
TypedStatement::Empty => vec![]
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions package/origlang-typesystem-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ pub enum TypedStatement {
expression: TypedExpression,
},
Exit,
// TODO: eventually this would not be needed!
Empty,
}

#[derive(Clone, Eq, PartialEq, Debug)]
Expand Down

0 comments on commit cfd4596

Please sign in to comment.