diff --git a/GRAMMER.md b/GRAMMER.md index bc1ea95..e873c63 100644 --- a/GRAMMER.md +++ b/GRAMMER.md @@ -4,145 +4,170 @@ ** use a tool to validate this...** ## Statements -``` -Stmt ::= ExprStmt | WhileLoop | DoWhileLoop | - ForLoop | IfElse | Declaration | - Block . -Chunk ::= {Stmt [";"]} [LastStmt [";"]] . -Block ::= "{" Chunk "}" . -LastStmt ::= "return" [Expr] | "continue" | "break" . -ExprStmt ::= Operand "=" Expr | Call | Match . +```ebnf +Stmt = ExprStmt | WhileStmt | DoWhileStmt | + ForStmt | IfElse | Declaration | + Block . +Chunk = {Stmt [";"]} [LastStmt [";"]] . +Block = "{" Chunk "}" . +LastStmt = "return" [Expr] | "continue" | "break" . +ExprStmt = Operand "=" Expr | Call | Match . ``` ### Control flow -``` -IfElse ::= "if" Expr Block [{"else" IfElse} | "else" Block] . -WhileLoop ::= "while" Expr Block . -DoWhileLoop ::= "do" Block "while" Expr . -ForLoop ::= ForIn | ForNum . -ForIn ::= "for" name "in" Expr Block . -ForNum ::= "for" name "=" Expr "," Expr ["," Expr] Block . -Match ::= "match" Expr MatchBody . -MatchBody ::= "{" {MatchArm ","} MatchArm "}" . -MatchClause ::= Expr "=>" MatchArm . -MatchArm ::= Expr | Block . +```ebnf +IfElse = "if" Expr Block [{"else" IfElse} | "else" Block] . +WhileStmt = "while" Expr Block . +DoWhileStmt = "do" Block "while" Expr . +ForStmt = ForIn | ForNum . +ForIn = "for" name "in" Expr Block . +ForNum = "for" name "=" Expr "," Expr ["," Expr] Block . ``` -## Declarations +## Pattern matching +```ebnf +MatchExpr = "match" Expr MatchBody . +MatchBody = "{" {MatchArm ","} MatchArm "}" . +MatchClause = Pattern "=>" MatchArm . +MatchArm = Expr | Block . ``` -Declaration ::= VarDecl | FunctionDecl | - ClassDecl | EnumDecl | TypeDecl . -VarDecl ::= "let" name [":" Type] "=" Expr . -TypeDecl ::= "type" name [TypeParam] "=" Type . -TypeParam ::= "[" {name ","} name "]" . + +## Paths +TODO: 'Suffixed expressions' can be split up into a path, possibly followed by a '.', '?', '(', or '{'. +TODO: The suffix after the path cannot contain '::', since any of the aformentioned tokens resolve to a value, as opposed to a type +```ebnf +Path = {Segment "::"} Segment . +Segment = name [TypeArgs] . ``` -### Functions +## Patterns +```ebnf +Pattern = LiteralPat | TuplePat | StructPat | + VariantPat | PathPat | RangePat . +LiteralPat = StrPat | IntPat | BoolPat . +RangePat = Pattern RangeSep Pattern . +RangeSep = ".." | "..=" . +PatList = {Pattern ","} Pattern [","] . +TuplePat = "(" [{Pattern ","} Pattern "," [Pattern]] ")". +VariantPat = Path "(" PatList ")" . +StructPat = Path "{" PatList "}" . +PathPat = Path . ``` -FunctionDecl ::= "fn" Function . -Function ::= name [TypeParam] FuncType Block . -FuncType ::= "(" [{Field ","} Field] ")" ["->" Type] . -Field ::= name ":" Type . + +## Declarations +```ebnf +Declaration = VarDecl | FunctionDecl | StructDecl | + EnumDecl | TypeDecl . +VarDecl = "let" name [":" Type] "=" Expr . +TypeDecl = "type" name [Generics] "=" Type . +Generics = "[" {name ","} name "]" . ``` -### Classes +### Functions +```ebnf +FunctionDecl = "fn" Function . +Function = name [Generics] FuncHead Block . +FuncHead = "(" [{Field ","} Field] ")" ["->" Type] . +Field = name ":" Type . ``` -ClassDecl ::= "class" ClassType . -ClassType ::= name [TypeParam] ClassBody . -ClassBody ::= "{" {Attribute [";"]} "}" . -Attribute ::= Method | Field . -Method ::= ["static"] Function . + +### Structures +```ebnf +StructDecl = "struct" name [Generics] StructBody . +StructBody = "{" {Field [";"]} "}" . ``` ### Enumerators -``` -EnumDecl ::= "enum" name EnumBody . -EnumBody ::= "{" [{Variant ","} Variant] "}" . -Variant ::= name [Payload] . -Payload ::= "(" {Type ","} Type ")" . +```ebnf +EnumDecl = "enum" name [Generics] EnumBody . +EnumBody = "{" [{Variant ","} Variant] "}" . +Variant = name [Payload] . +Payload = "(" {Type ","} Type ")" . ``` ## Operators -``` -BinOp ::= "+" | "-" | "*" | "/" | - "%" | "&" | "^" | "|" | - "<" | "<=" | ">" | ">=" | - "==" | "!=" | "&&" | "||" . -UnOp ::= "-" | "~" | "!" | "#" . +```ebnf +BinOp = "+" | "-" | "*" | "/" | + "%" | "&" | "^" | "|" | + "<" | "<=" | ">" | ">=" | + "==" | "!=" | "&&" | "||" . +UnOp = "-" | "~" | "!" | "#" . ``` ## Expressions -``` -Expr ::= PrimaryExpr | Expr BinOp Expr | UnOp Expr . -PrimaryExpr ::= Operand | Call | Literal | "(" Expr ")" . -Call ::= PrimaryExpr "(" [ExprList] ")" . -Operand ::= name | Index | Selector . -Index ::= PrimaryExpr "[" ExprList "]" . -Selector ::= PrimaryExpr "." name . -ExprList ::= {Expr ","} Expr . +```ebnf +Expr = PrimaryExpr | Expr BinOp Expr | UnOp Expr . +PrimaryExpr = Operand | Call | "(" Expr ")" . +Call = PrimaryExpr "(" [ExprList] ")" . +Index = PrimaryExpr "[" ExprList "]" . +Selector = PrimaryExpr "." name . +ExprList = {Expr ","} Expr . ``` ## Types -``` -Type ::= name [TypeArgs] | TypeLit . -TypeLit ::= FuncType | ArrayType | TupleType . -FuncType ::= "fn" "(" [TypeList] ")" ["->" Type] . -TypeList ::= {Type ","} Type -TypeArgs ::= "[" TypeList "]" . -NamedType ::= name [TypeArgs] . -ArrayType ::= "[" Type ";" int_lit "]" . -TupleType ::= "(" [Type "," [Type]] ")" . +```ebnf +Type = NamedType | TypeLit . +TypeLit = FuncType | VectorType | MapType | + TupleType | NamedType . +FuncType = "fn" "(" [TypeList] ")" ["->" Type] . +TypeList = {Type ","} Type . +TypeArgs = "[" TypeList "]" . +NamedType = name [TypeArgs] . +VectorType = "[" Type "]" . +MapType = "[" Type ":" Type "]" . +TupleType = "(" [{Type ","} Type "," [Type]] ")". ``` ## Operands -``` -Operand ::= Literal | name [TypeArgs] . -Literal ::= BasicLit | CompositeLit . -BasicLit ::= int_lit | bool_lit | float_lit | string_lit . +```ebnf +Operand = Path | Index | Selector | Literal . +Literal = BasicLit | CompositeLit . +BasicLit = int_lit | bool_lit | float_lit | string_lit . ``` ### Composite literals Note that the unit type is just a 0-tuple (an tuple with 0 elements). A 1-tuple must have a trailing `,` to distinguish it from a parenthesized expression. -``` -CompositeLit ::= ClassLit | ArrayLit | TupleLit | VariantLit . -ClassLit ::= NamedType "{" [ItemList [","]] "}" . -ArrayLit ::= "[" [ExprList [","]] "]" . -TupleLit ::= "(" [Expr "," [Expr [","]]] ")" . -VariantLit ::= name ["(" {Expr ","} Expr ")"] . -ItemList ::= KeyedItem {"," KeyedItem} [","] . -KeyedItem ::= [Key ":"] Expr . -Key ::= name | Expr . +```ebnf +CompositeLit = VectorLit | MapLit | TupleLit | StructLit | VariantLit . +VectorLit = "[" [ExprList [","]] "]" . +MapLit = "[" ":" "]" | "[" [ItemList [","]] "]" . +TupleLit = "(" [{Expr ","} Expr "," [Expr]] ")". +StructLit = Path "{" [ItemList [","]] "}" . +VariantLit = Path ["(" {Expr ","} Expr ")"] . +ItemList = KeyedItem {"," KeyedItem} [","] . +KeyedItem = [Key ":"] Expr . +Key = name | Expr . ``` ### Integer literals -``` -int_lit ::= decimal_lit | binary_lit | octal_lit | hex_lit . -decimal_lit ::= "0" | ("1" … "9") [decimal_digits] . -binary_lit ::= "0" ("b" | "B") binary_digits . -octal_lit ::= "0" ("o" | "O") octal_digits . -hex_lit ::= "0" ("x" | "X") hex_digits . +```ebnf +int_lit = decimal_lit | binary_lit | octal_lit | hex_lit . +decimal_lit = "0" | ("1" … "9") [decimal_digits] . +binary_lit = "0" ("b" | "B") binary_digits . +octal_lit = "0" ("o" | "O") octal_digits . +hex_lit = "0" ("x" | "X") hex_digits . ``` ### Float literals -``` -float_lit := decimal_digits "." [decimal_digits] [decimal_exponent] | - decimal_digits decimal_exponent | - "." decimal_digits [decimal_exponent] . -decimal_exponent := ("e" | "E") ["+" | "-"] decimal_digits . +```ebnf +float_lit = decimal_digits "." [decimal_digits] [decimal_exponent] | + decimal_digits decimal_exponent | + "." decimal_digits [decimal_exponent] . +decimal_exponent = ("e" | "E") ["+" | "-"] decimal_digits . ``` ## Miscellaneous -``` -name ::= letter {letter | decimal_digit} . -letter ::= "A" … "Z" | "a" … "z" | "_" . -decimal_digit ::= "0" … "9" . -binary_digit ::= "0" | "1" . -octal_digit ::= "0" … "7" . -hex_digit ::= "0" … "9" | "A" … "F" | "a" … "f" . -decimal_digits ::= decimal_digit {decimal_digit} . -binary_digits ::= binary_digit {binary_digit} . -octal_digits ::= octal_digit {octal_digit} . -hex_digits ::= hex_digit {hex_digit} . +```ebnf +name = letter {letter | decimal_digit} . +letter = "A" … "Z" | "a" … "z" | "_" . +decimal_digit = "0" … "9" . +binary_digit = "0" | "1" . +octal_digit = "0" … "7" . +hex_digit = "0" … "9" | "A" … "F" | "a" … "f" . +decimal_digits = decimal_digit {decimal_digit} . +binary_digits = binary_digit {binary_digit} . +octal_digits = octal_digit {octal_digit} . +hex_digits = hex_digit {hex_digit} . ``` diff --git a/README.md b/README.md index b147799..69a3273 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,147 @@ assert(status != 0) + [ ] metamethods + [ ] existential types +## Pattern matching notes + +### Match construct +Identifiers in a match guard create new variable bindings, given that they don't refer to exiting **types** (variables are shadowed). +Each identifier can be bound at most 1 time per guard (`E::X(a, b, a)` is not allowed). +A match construct eventually becomes a series of comparisons and jumps, similar to an if-else chain. +``` +struct S {v: float} +enum D {A, B(string)} +enum E {X, Y(int), Z(S), W(D)} +let e = select_variant() +let v = match e { + E::X => 0, + E::Y(1) => 1, + E::Y(i) => i, + E::Z(S{v}) if v < 0.0 => 4, + E::Z(S{v: renamed}) => int(renamed), + E::W(D::A) => 6, + E::W(D::B(s)) if #s > 1 => #s, + E::W(d) => 8, + _ => 9, +} +``` + +### Desugared code +``` +let v = while 1 { + if disc(e) == 0 { + break 0 + } + if disc(e) == 1 { + if e.0 == 1 { + break 1 + } + } + if disc(e) == 1 { + let i = e.0 + break i + } + if disc(e) == 2 { + let v = e.0.v + if v < 0.0 { + break 4 + } + } + if disc(e) == 2 { + let renamed = e.0.v + break int(renamed) + } + if disc(e) == 3 { + if disc(e.0) == 0 { + break 6 + } + } + if disc(e) == 3 { + if disc(e.0) == 1 { + let s = e.0.0 + if #s > 1 { + break #s + } + } + } + if disc(e) == 3 { + let d = e.0 + break 8 + } + // TODO: exhaustiveness check + break 9 +} +``` + +### Desugared code with merged cases +Cases can be moved around, but cannot 'cross' another case selecting the same variant, otherwise the semantics of the program might be changed. +``` +let v = while 1 { + if disc(e) == 0 { + break 0 + } + if disc(e) == 1 { + if e.0 == 1 { + break 1 + } else { + let i = e.0 + break i + } + } + if disc(e) == 2 { + { // careful about scope. although, it may not matter too much if we have already resolved variable accesses + let v = e.0.v + if v < 0.0 { + break 4 + } + } + let renamed = e.0.v + break int(renamed) + } + if disc(e) == 3 { + if disc(e.0) == 0 { + break 6 + } else if disc(e.0) == 1 { + let s = e.0.0 + if #s > 1 { + break #s + } + } else { + break 8 + } + } + // TODO: exhaustiveness check + break 9 +} +``` + + +### Possible opcodes +``` + OP_COPY + OP_MATCHVARIANT(0) + OP_JUMPFALSE('next1') // patch locally + OP_POP(1) + OP_PUSHCONST(0) + OP_TRANSIT(1) + OP_JUMP('out') // save until the end, in label list +next1: + OP_COPY + OP_MATCHVARIANT(1) + OP_JUMPF('next2') + OP_POP(1) + OP_GETFIELD(0) + OP_PUSHCONST(1) + OP_BINARY('==') + OP_JUMPF('next2') + OP_POP(1) + OP_PUSHCONST(1) + OP_TRANSIT(1) + OP_JUMP('out') +next2: + ... +out: +``` + ## References + [Lua](https://www.lua.org/) + [MicroPython](https://micropython.org/) diff --git a/src/api.c b/src/api.c index 64a859c..9a06802 100644 --- a/src/api.c +++ b/src/api.c @@ -119,11 +119,6 @@ paw_Bool paw_is_function(paw_Env *P, int index) return paw_type(P, index) == PAW_TFUNCTION; } -paw_Bool paw_is_array(paw_Env *P, int index) -{ - return paw_type(P, index) == PAW_TVECTOR; -} - paw_Bool paw_is_tuple(paw_Env *P, int index) { return paw_type(P, index) == PAW_TTUPLE; diff --git a/src/api.h b/src/api.h index d505f39..02e11cd 100644 --- a/src/api.h +++ b/src/api.h @@ -20,12 +20,12 @@ static inline const char *api_typename(int type) return "float"; case PAW_TSTRING: return "string"; - case PAW_TVECTOR: - return "vector"; case PAW_TFUNCTION: return "function"; case PAW_TSTRUCT: return "struct"; + case PAW_TENUM: + return "enum"; case PAW_TFOREIGN: return "foreign"; default: diff --git a/src/ast.c b/src/ast.c index e4a48dc..82b659f 100644 --- a/src/ast.c +++ b/src/ast.c @@ -7,13 +7,16 @@ #include "mem.h" #include #include +#include #define FIRST_ARENA_SIZE 512 static void add_builtin_type(Ast *ast, AstTypeKind kind, paw_Type code) { ast->builtin[code] = pawA_new_type(ast, kind); - ast->builtin[code]->hdr.def = code; + ast->builtin[code]->adt.types = pawA_list_new(ast); + ast->builtin[code]->adt.base = code; + ast->builtin[code]->adt.did = code; } Ast *pawA_new_ast(Lex *lex) @@ -21,16 +24,17 @@ Ast *pawA_new_ast(Lex *lex) paw_Env *P = env(lex); Ast *tree = pawM_new(P, Ast); tree->lex = lex; + // initialize memory pools for storing AST components pawK_pool_init(P, &tree->nodes, FIRST_ARENA_SIZE, sizeof(AstDecl)); pawK_pool_init(P, &tree->symbols, FIRST_ARENA_SIZE, sizeof(Symbol)); pawK_pool_init(P, &tree->sequences, FIRST_ARENA_SIZE, sizeof(void *) * 8); - add_builtin_type(tree, AST_TYPE_BASIC, PAW_TUNIT); - add_builtin_type(tree, AST_TYPE_BASIC, PAW_TBOOL); - add_builtin_type(tree, AST_TYPE_BASIC, PAW_TINT); - add_builtin_type(tree, AST_TYPE_BASIC, PAW_TFLOAT); - add_builtin_type(tree, AST_TYPE_BASIC, PAW_TSTRING); + add_builtin_type(tree, AST_TYPE_ADT, PAW_TUNIT); + add_builtin_type(tree, AST_TYPE_ADT, PAW_TBOOL); + add_builtin_type(tree, AST_TYPE_ADT, PAW_TINT); + add_builtin_type(tree, AST_TYPE_ADT, PAW_TFLOAT); + add_builtin_type(tree, AST_TYPE_ADT, PAW_TSTRING); return tree; } @@ -55,6 +59,7 @@ void pawA_free_ast(Ast *ast) make_node_constructor(expr, AstExpr) make_node_constructor(decl, AstDecl) make_node_constructor(stmt, AstStmt) +make_node_constructor(pat, AstPat) // clang-format on #define LIST_MIN_ALLOC 8 @@ -128,6 +133,17 @@ void pawA_list_push(Ast *ast, AstList **plist, void *node) *plist = list; } +void pawA_path_push(Ast *ast, AstList **ppath, String *name, AstList *types) +{ + Lex *lex = ast->lex; + AstPathSegment *segment = pawK_pool_alloc(env(lex), &lex->pm->ast->nodes, + sizeof(AstPathSegment), + paw_alignof(Symbol)); + segment->name = name; + segment->types = types; + pawA_list_push(ast, ppath, segment); +} + Symbol *pawA_new_symbol(Lex *lex) { return pawK_pool_alloc(env(lex), &lex->pm->ast->symbols, sizeof(Symbol), @@ -204,13 +220,6 @@ static void visit_chain_expr(AstVisitor *V, ChainExpr *e) V->visit_expr(V, e->target); } -static void visit_cond_expr(AstVisitor *V, CondExpr *e) -{ - V->visit_expr(V, e->cond); - V->visit_expr(V, e->lhs); - V->visit_expr(V, e->rhs); -} - static void visit_unop_expr(AstVisitor *V, UnOpExpr *e) { V->visit_expr(V, e->target); @@ -231,14 +240,29 @@ static void visit_expr_stmt(AstVisitor *V, AstExprStmt *s) static void visit_signature_expr(AstVisitor *V, FuncType *e) { visit_exprs(V, e->params); - V->visit_expr(V, e->return_); + V->visit_expr(V, e->result); } -static void visit_type_name_expr(AstVisitor *V, TypeName *e) +static void visit_typename_expr(AstVisitor *V, TypeName *e) { - if (e->args != NULL) { - visit_exprs(V, e->args); - } + visit_exprs(V, e->args); +} + +static void visit_typelist_expr(AstVisitor *V, TypeList *e) +{ + visit_exprs(V, e->types); +} + +static void visit_match_expr(AstVisitor *V, MatchExpr *e) +{ + V->visit_expr(V, e->target); + visit_exprs(V, e->arms); +} + +static void visit_arm_expr(AstVisitor *V, MatchArm *e) +{ + V->visit_pat(V, e->guard); + V->visit_expr(V, e->value); } static void visit_field_decl(AstVisitor *V, FieldDecl *d) @@ -285,6 +309,11 @@ static void visit_call_expr(AstVisitor *V, CallExpr *e) visit_exprs(V, e->args); } +static void visit_conversion_expr(AstVisitor *V, ConversionExpr *e) +{ + V->visit_expr(V, e->arg); +} + static void visit_ident_expr(AstVisitor *V, AstIdent *e) { paw_unused(V); @@ -297,7 +326,7 @@ static void visit_func_decl(AstVisitor *V, FuncDecl *d) visit_decls(V, d->generics); } visit_decls(V, d->params); - V->visit_expr(V, d->return_); + V->visit_expr(V, d->result); V->visit_block_stmt(V, d->body); } @@ -344,11 +373,51 @@ static void visit_index_expr(AstVisitor *V, Index *e) visit_exprs(V, e->elems); } +static void visit_access_expr(AstVisitor *V, Access *e) +{ + V->visit_expr(V, e->target); +} + static void visit_selector_expr(AstVisitor *V, Selector *e) { V->visit_expr(V, e->target); } +static void visit_literal_pat(AstVisitor *V, AstLiteralPat *p) +{ + V->visit_expr(V, p->expr); +} + +static void visit_path_pat(AstVisitor *V, AstPathPat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void visit_tuple_pat(AstVisitor *V, AstTuplePat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void visit_field_pat(AstVisitor *V, AstFieldPat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void visit_struct_pat(AstVisitor *V, AstStructPat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void visit_variant_pat(AstVisitor *V, AstVariantPat *p) +{ + paw_unused(V); + paw_unused(p); +} + static void visit_expr(AstVisitor *V, AstExpr *expr) { if (expr == NULL) { @@ -370,12 +439,12 @@ static void visit_expr(AstVisitor *V, AstExpr *expr) case EXPR_BINOP: V->visit_binop_expr(V, &expr->binop); break; + case EXPR_CONVERSION: + V->visit_conversion_expr(V, &expr->conv); + break; case EXPR_CALL: V->visit_call_expr(V, &expr->call); break; - case EXPR_COND: - V->visit_cond_expr(V, &expr->cond); - break; case EXPR_NAME: V->visit_ident_expr(V, &expr->name); break; @@ -385,11 +454,23 @@ static void visit_expr(AstVisitor *V, AstExpr *expr) case EXPR_ITEM: V->visit_item_expr(V, &expr->item); break; - case EXPR_FUNC_TYPE: + case EXPR_FUNCTYPE: V->visit_signature_expr(V, &expr->func); break; - case EXPR_TYPE_NAME: - V->visit_type_name_expr(V, &expr->type_name); + case EXPR_TYPENAME: + V->visit_typename_expr(V, &expr->type_name); + break; + case EXPR_TYPELIST: + V->visit_typelist_expr(V, &expr->typelist); + break; + case EXPR_ACCESS: + V->visit_access_expr(V, &expr->access); + break; + case EXPR_MATCH: + V->visit_match_expr(V, &expr->match); + break; + case EXPR_MATCHARM: + V->visit_arm_expr(V, &expr->arm); break; default: paw_assert(a_kind(expr) == EXPR_SELECTOR); @@ -418,6 +499,9 @@ static void visit_decl(AstVisitor *V, AstDecl *decl) case DECL_FUNC: V->visit_func_decl(V, &decl->func); break; + case DECL_VARIANT: + V->visit_variant_decl(V, &decl->variant); + break; default: paw_assert(a_kind(decl) == DECL_STRUCT); V->visit_struct_decl(V, &decl->struct_); @@ -466,6 +550,34 @@ static void visit_stmt(AstVisitor *V, AstStmt *stmt) } } +static void visit_pat(AstVisitor *V, AstPat *pat) +{ + if (pat == NULL) { + return; + } + switch (a_kind(pat)) { + case AST_PAT_LITERAL: + V->visit_literal_pat(V, &pat->literal); + break; + case AST_PAT_PATH: + V->visit_path_pat(V, &pat->path); + break; + case AST_PAT_FIELD: + V->visit_field_pat(V, &pat->field); + break; + case AST_PAT_TUPLE: + V->visit_tuple_pat(V, &pat->tuple); + break; + case AST_PAT_VARIANT: + V->visit_variant_pat(V, &pat->variant); + break; + default: + paw_assert(a_kind(pat) == AST_PAT_STRUCT); + V->visit_struct_pat(V, &pat->struct_); + break; + } +} + void pawA_visitor_init(AstVisitor *V, Ast *ast, AstState state) { *V = (AstVisitor){ @@ -474,6 +586,7 @@ void pawA_visitor_init(AstVisitor *V, Ast *ast, AstState state) .visit_expr = visit_expr, .visit_decl = visit_decl, .visit_stmt = visit_stmt, + .visit_pat = visit_pat, .visit_expr_list = visit_expr_list_aux, .visit_decl_list = visit_decl_list_aux, .visit_stmt_list = visit_stmt_list_aux, @@ -483,13 +596,17 @@ void pawA_visitor_init(AstVisitor *V, Ast *ast, AstState state) .visit_chain_expr = visit_chain_expr, .visit_unop_expr = visit_unop_expr, .visit_binop_expr = visit_binop_expr, - .visit_cond_expr = visit_cond_expr, .visit_call_expr = visit_call_expr, + .visit_conversion_expr = visit_conversion_expr, .visit_index_expr = visit_index_expr, + .visit_access_expr = visit_access_expr, .visit_selector_expr = visit_selector_expr, .visit_item_expr = visit_item_expr, - .visit_type_name_expr = visit_type_name_expr, + .visit_typename_expr = visit_typename_expr, + .visit_typelist_expr = visit_typelist_expr, .visit_signature_expr = visit_signature_expr, + .visit_match_expr = visit_match_expr, + .visit_arm_expr = visit_arm_expr, .visit_block_stmt = visit_block_stmt, .visit_expr_stmt = visit_expr_stmt, .visit_decl_stmt = visit_decl_stmt, @@ -505,6 +622,12 @@ void pawA_visitor_init(AstVisitor *V, Ast *ast, AstState state) .visit_field_decl = visit_field_decl, .visit_generic_decl = visit_generic_decl, .visit_type_decl = visit_type_decl, + .visit_literal_pat = visit_literal_pat, + .visit_path_pat = visit_path_pat, + .visit_tuple_pat = visit_tuple_pat, + .visit_field_pat = visit_field_pat, + .visit_struct_pat = visit_struct_pat, + .visit_variant_pat = visit_variant_pat, }; } @@ -580,14 +703,6 @@ static AstExpr *fold_chain_expr(AstFolder *F, ChainExpr *e) return cast_expr(e); } -static AstExpr *fold_cond_expr(AstFolder *F, CondExpr *e) -{ - e->cond = F->fold_expr(F, e->cond); - e->lhs = F->fold_expr(F, e->lhs); - e->rhs = F->fold_expr(F, e->rhs); - return cast_expr(e); -} - static AstExpr *fold_unop_expr(AstFolder *F, UnOpExpr *e) { e->target = F->fold_expr(F, e->target); @@ -611,15 +726,33 @@ static AstStmt *fold_expr_stmt(AstFolder *F, AstExprStmt *s) static AstExpr *fold_signature_expr(AstFolder *F, FuncType *e) { fold_exprs(F, e->params); - e->return_ = F->fold_expr(F, e->return_); + e->result = F->fold_expr(F, e->result); return cast_expr(e); } -static AstExpr *fold_type_name_expr(AstFolder *F, TypeName *e) +static AstExpr *fold_typename_expr(AstFolder *F, TypeName *e) { - if (e->args != NULL) { - fold_exprs(F, e->args); - } + fold_exprs(F, e->args); + return cast_expr(e); +} + +static AstExpr *fold_typelist_expr(AstFolder *F, TypeList *e) +{ + fold_exprs(F, e->types); + return cast_expr(e); +} + +static AstExpr *fold_match_expr(AstFolder *F, MatchExpr *e) +{ + e->target = F->fold_expr(F, e->target); + fold_exprs(F, e->arms); + return cast_expr(e); +} + +static AstExpr *fold_arm_expr(AstFolder *F, MatchArm *e) +{ + e->guard = F->fold_pat(F, e->guard); + e->value = F->fold_expr(F, e->value); return cast_expr(e); } @@ -669,6 +802,12 @@ static AstExpr *fold_call_expr(AstFolder *F, CallExpr *e) return cast_expr(e); } +static AstExpr *fold_conversion_expr(AstFolder *F, ConversionExpr *e) +{ + e->arg = F->fold_expr(F, e->arg); + return cast_expr(e); +} + static AstExpr *fold_ident_expr(AstFolder *F, AstIdent *e) { paw_unused(F); @@ -679,7 +818,7 @@ static AstDecl *fold_func_decl(AstFolder *F, FuncDecl *d) { fold_decls(F, d->generics); fold_decls(F, d->params); - d->return_ = F->fold_expr(F, d->return_); + d->result = F->fold_expr(F, d->result); d->body = fold_block(F, d->body); return cast_decl(d); } @@ -731,6 +870,48 @@ static AstExpr *fold_selector_expr(AstFolder *F, Selector *e) return cast_expr(e); } +static AstExpr *fold_access_expr(AstFolder *F, Access *e) +{ + e->target = F->fold_expr(F, e->target); + return cast_expr(e); +} + +static AstPat *fold_literal_pat(AstFolder *F, AstLiteralPat *p) +{ + p->expr = F->fold_expr(F, p->expr); + return cast_pat(p); +} + +static AstPat *fold_path_pat(AstFolder *V, AstPathPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *fold_tuple_pat(AstFolder *V, AstTuplePat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *fold_field_pat(AstFolder *V, AstFieldPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *fold_struct_pat(AstFolder *V, AstStructPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *fold_variant_pat(AstFolder *V, AstVariantPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + static AstExpr *fold_expr(AstFolder *F, AstExpr *expr) { if (expr == NULL) { @@ -747,20 +928,28 @@ static AstExpr *fold_expr(AstFolder *F, AstExpr *expr) return F->fold_unop_expr(F, &expr->unop); case EXPR_BINOP: return F->fold_binop_expr(F, &expr->binop); + case EXPR_CONVERSION: + return F->fold_conversion_expr(F, &expr->conv); case EXPR_CALL: return F->fold_call_expr(F, &expr->call); - case EXPR_COND: - return F->fold_cond_expr(F, &expr->cond); case EXPR_NAME: return F->fold_ident_expr(F, &expr->name); case EXPR_INDEX: return F->fold_index_expr(F, &expr->index); case EXPR_ITEM: return F->fold_item_expr(F, &expr->item); - case EXPR_FUNC_TYPE: + case EXPR_FUNCTYPE: return F->fold_signature_expr(F, &expr->func); - case EXPR_TYPE_NAME: - return F->fold_type_name_expr(F, &expr->type_name); + case EXPR_TYPENAME: + return F->fold_typename_expr(F, &expr->type_name); + case EXPR_TYPELIST: + return F->fold_typelist_expr(F, &expr->typelist); + case EXPR_MATCH: + return F->fold_match_expr(F, &expr->match); + case EXPR_MATCHARM: + return F->fold_arm_expr(F, &expr->arm); + case EXPR_ACCESS: + return F->fold_access_expr(F, &expr->access); default: paw_assert(a_kind(expr) == EXPR_SELECTOR); return F->fold_selector_expr(F, &expr->selector); @@ -785,6 +974,8 @@ static AstDecl *fold_decl(AstFolder *F, AstDecl *decl) return F->fold_func_decl(F, &decl->func); case DECL_INSTANCE: return F->fold_instance_decl(F, &decl->inst); + case DECL_VARIANT: + return F->fold_variant_decl(F, &decl->variant); default: paw_assert(a_kind(decl) == DECL_STRUCT); return F->fold_struct_decl(F, &decl->struct_); @@ -825,6 +1016,28 @@ static AstStmt *fold_stmt(AstFolder *F, AstStmt *stmt) } } +static AstPat *fold_pat(AstFolder *F, AstPat *pat) +{ + if (pat == NULL) { + return NULL; + } + switch (a_kind(pat)) { + case AST_PAT_LITERAL: + return F->fold_literal_pat(F, &pat->literal); + case AST_PAT_PATH: + return F->fold_path_pat(F, &pat->path); + case AST_PAT_FIELD: + return F->fold_field_pat(F, &pat->field); + case AST_PAT_TUPLE: + return F->fold_tuple_pat(F, &pat->tuple); + case AST_PAT_VARIANT: + return F->fold_variant_pat(F, &pat->variant); + default: + paw_assert(a_kind(pat) == AST_PAT_STRUCT); + return F->fold_struct_pat(F, &pat->struct_); + } +} + void pawA_fold_init(AstFolder *F, Ast *ast, AstState state) { *F = (AstFolder){ @@ -833,6 +1046,7 @@ void pawA_fold_init(AstFolder *F, Ast *ast, AstState state) .fold_expr = fold_expr, .fold_decl = fold_decl, .fold_stmt = fold_stmt, + .fold_pat = fold_pat, .fold_expr_list = fold_expr_list, .fold_decl_list = fold_decl_list, .fold_stmt_list = fold_stmt_list, @@ -842,12 +1056,16 @@ void pawA_fold_init(AstFolder *F, Ast *ast, AstState state) .fold_chain_expr = fold_chain_expr, .fold_unop_expr = fold_unop_expr, .fold_binop_expr = fold_binop_expr, - .fold_cond_expr = fold_cond_expr, + .fold_conversion_expr = fold_conversion_expr, .fold_call_expr = fold_call_expr, .fold_index_expr = fold_index_expr, .fold_selector_expr = fold_selector_expr, + .fold_access_expr = fold_access_expr, + .fold_match_expr = fold_match_expr, + .fold_arm_expr = fold_arm_expr, .fold_item_expr = fold_item_expr, - .fold_type_name_expr = fold_type_name_expr, + .fold_typename_expr = fold_typename_expr, + .fold_typelist_expr = fold_typelist_expr, .fold_signature_expr = fold_signature_expr, .fold_block_stmt = fold_block_stmt, .fold_expr_stmt = fold_expr_stmt, @@ -863,6 +1081,12 @@ void pawA_fold_init(AstFolder *F, Ast *ast, AstState state) .fold_field_decl = fold_field_decl, .fold_generic_decl = fold_generic_decl, .fold_type_decl = fold_type_decl, + .fold_literal_pat = fold_literal_pat, + .fold_path_pat = fold_path_pat, + .fold_tuple_pat = fold_tuple_pat, + .fold_field_pat = fold_field_pat, + .fold_struct_pat = fold_struct_pat, + .fold_variant_pat = fold_variant_pat, }; } @@ -880,17 +1104,18 @@ static void fold_binder(AstTypeFolder *F, AstList *binder) } } -static AstType *fold_basic(AstTypeFolder *F, AstTypeHeader *t) +static AstType *fold_func(AstTypeFolder *F, AstFuncDef *t) { - paw_unused(F); + F->fold_binder(F, t->types); + F->fold_binder(F, t->params); + t->result = F->fold(F, t->result); return a_cast_type(t); } -static AstType *fold_func(AstTypeFolder *F, AstFuncSig *t) +static AstType *fold_fptr(AstTypeFolder *F, AstFuncPtr *t) { - F->fold_binder(F, t->types); F->fold_binder(F, t->params); - t->return_ = F->fold(F, t->return_); + t->result = F->fold(F, t->result); return a_cast_type(t); } @@ -918,7 +1143,7 @@ void pawA_type_folder_init(AstTypeFolder *F, void *state) .state = state, .fold = pawA_fold_type, .fold_binder = fold_binder, - .fold_basic = fold_basic, + .fold_fptr = fold_fptr, .fold_func = fold_func, .fold_adt = fold_adt, .fold_unknown = fold_unknown, @@ -929,16 +1154,16 @@ void pawA_type_folder_init(AstTypeFolder *F, void *state) AstType *pawA_fold_type(AstTypeFolder *F, AstType *type) { switch (y_kind(type)) { - case AST_TYPE_BASIC: - return F->fold_basic(F, &type->hdr); case AST_TYPE_GENERIC: return F->fold_generic(F, &type->generic); case AST_TYPE_UNKNOWN: return F->fold_unknown(F, &type->unknown); case AST_TYPE_ADT: return F->fold_adt(F, &type->adt); + case AST_TYPE_FPTR: + return F->fold_fptr(F, &type->fptr); default: - paw_assert(a_is_func(type)); + paw_assert(a_is_fdef(type)); return F->fold_func(F, &type->func); } } @@ -952,6 +1177,7 @@ typedef struct Copier { Ast *ast; // AST being copied } Copier; +// clang-format off #define make_copy_prep(name, T) \ static T *copy_prep_##name##_aux(AstFolder *F, T *t) \ { \ @@ -960,14 +1186,17 @@ typedef struct Copier { r->hdr.line = t->hdr.line; \ return r; \ } -make_copy_prep(expr, AstExpr) make_copy_prep(decl, AstDecl) - make_copy_prep(stmt, AstStmt) +make_copy_prep(expr, AstExpr) +make_copy_prep(decl, AstDecl) +make_copy_prep(stmt, AstStmt) +make_copy_prep(pat, AstPat) // Helpers for copying: create a new node of the given type and kind, // and copy the common fields #define copy_prep_expr(F, e) copy_prep_expr_aux(F, cast_expr(e)) #define copy_prep_decl(F, d) copy_prep_decl_aux(F, cast_decl(d)) #define copy_prep_stmt(F, s) copy_prep_stmt_aux(F, cast_stmt(s)) +#define copy_prep_pat(F, p) copy_prep_pat_aux(F, cast_pat(p)) #define make_copy_list(name, T) \ static AstList *copy_##name##s(AstFolder *F, AstList *old_list) \ @@ -979,16 +1208,18 @@ make_copy_prep(expr, AstExpr) make_copy_prep(decl, AstDecl) F->fold_##name##_list(F, new_list, F->fold_##name); \ return new_list; \ } - make_copy_list(decl, AstDecl) make_copy_list(expr, AstExpr) - make_copy_list(stmt, AstStmt) +make_copy_list(decl, AstDecl) +make_copy_list(expr, AstExpr) +make_copy_list(stmt, AstStmt) - static AstStmt *copy_block_stmt(AstFolder *F, Block *s) +static AstStmt *copy_block_stmt(AstFolder *F, Block *s) { AstStmt *r = copy_prep_stmt(F, s); r->block.stmts = copy_stmts(F, s->stmts); return r; } #define copy_block(F, s) cast((F)->fold_block_stmt(F, s), Block *) +// clang-format on static AstExpr *copy_logical_expr(AstFolder *F, LogicalExpr *e) { @@ -1035,15 +1266,6 @@ static AstExpr *copy_chain_expr(AstFolder *F, ChainExpr *e) return r; } -static AstExpr *copy_cond_expr(AstFolder *F, CondExpr *e) -{ - AstExpr *r = copy_prep_expr(F, e); - r->cond.cond = F->fold_expr(F, e->cond); - r->cond.lhs = F->fold_expr(F, e->lhs); - r->cond.rhs = F->fold_expr(F, e->rhs); - return r; -} - static AstExpr *copy_unop_expr(AstFolder *F, UnOpExpr *e) { AstExpr *r = copy_prep_expr(F, e); @@ -1073,11 +1295,11 @@ static AstExpr *copy_signature_expr(AstFolder *F, FuncType *e) { AstExpr *r = copy_prep_expr(F, e); r->func.params = copy_exprs(F, e->params); - r->func.return_ = F->fold_expr(F, e->return_); + r->func.result = F->fold_expr(F, e->result); return r; } -static AstExpr *copy_type_name_expr(AstFolder *F, TypeName *e) +static AstExpr *copy_typename_expr(AstFolder *F, TypeName *e) { AstExpr *r = copy_prep_expr(F, e); r->type_name.name = e->name; @@ -1085,6 +1307,13 @@ static AstExpr *copy_type_name_expr(AstFolder *F, TypeName *e) return r; } +static AstExpr *copy_typelist_expr(AstFolder *F, TypeList *e) +{ + AstExpr *r = copy_prep_expr(F, e); + r->typelist.types = copy_exprs(F, e->types); + return r; +} + static AstDecl *copy_field_decl(AstFolder *F, FieldDecl *d) { AstDecl *r = copy_prep_decl(F, d); @@ -1119,6 +1348,15 @@ static AstDecl *copy_struct_decl(AstFolder *F, StructDecl *d) return r; } +static AstDecl *copy_variant_decl(AstFolder *F, VariantDecl *d) +{ + AstDecl *r = copy_prep_decl(F, d); + r->variant.name = d->name; + r->variant.fields = copy_decls(F, d->fields); + r->variant.index = d->index; + return r; +} + static AstDecl *copy_var_decl(AstFolder *F, VarDecl *d) { AstDecl *r = copy_prep_decl(F, d); @@ -1137,6 +1375,13 @@ static AstStmt *copy_return_stmt(AstFolder *F, ReturnStmt *s) return r; } +static AstExpr *copy_conversion_expr(AstFolder *F, ConversionExpr *e) +{ + AstExpr *r = copy_prep_expr(F, e); + r->conv.arg = F->fold_expr(F, e->arg); + return r; +} + static AstExpr *copy_call_expr(AstFolder *F, CallExpr *e) { AstExpr *r = copy_prep_expr(F, e); @@ -1160,7 +1405,7 @@ static AstDecl *copy_func_decl(AstFolder *F, FuncDecl *d) r->func.name = d->name; r->func.generics = copy_decls(F, d->generics); r->func.params = copy_decls(F, d->params); - r->func.return_ = F->fold_expr(F, d->return_); + r->func.result = F->fold_expr(F, d->result); r->func.body = copy_block(F, d->body); r->func.fn_kind = d->fn_kind; return r; @@ -1212,6 +1457,14 @@ static AstExpr *copy_index_expr(AstFolder *F, Index *e) return r; } +static AstExpr *copy_access_expr(AstFolder *F, Access *e) +{ + AstExpr *r = copy_prep_expr(F, e); + r->access.target = F->fold_expr(F, e->target); + r->access.name = e->name; + return r; +} + static AstExpr *copy_selector_expr(AstFolder *F, Selector *e) { AstExpr *r = copy_prep_expr(F, e); @@ -1227,6 +1480,36 @@ static AstStmt *copy_decl_stmt(AstFolder *F, AstDeclStmt *s) return r; } +static AstPat *copy_path_pat(AstFolder *V, AstPathPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *copy_tuple_pat(AstFolder *V, AstTuplePat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *copy_field_pat(AstFolder *V, AstFieldPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *copy_struct_pat(AstFolder *V, AstStructPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *copy_variant_pat(AstFolder *V, AstVariantPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + static void setup_copy_pass(AstFolder *F, Copier *C) { const AstState state = {.C = C}; @@ -1237,12 +1520,14 @@ static void setup_copy_pass(AstFolder *F, Copier *C) F->fold_chain_expr = copy_chain_expr; F->fold_unop_expr = copy_unop_expr; F->fold_binop_expr = copy_binop_expr; - F->fold_cond_expr = copy_cond_expr; + F->fold_conversion_expr = copy_conversion_expr; F->fold_call_expr = copy_call_expr; F->fold_index_expr = copy_index_expr; + F->fold_access_expr = copy_access_expr; F->fold_selector_expr = copy_selector_expr; F->fold_item_expr = copy_item_expr; - F->fold_type_name_expr = copy_type_name_expr; + F->fold_typename_expr = copy_typename_expr; + F->fold_typelist_expr = copy_typelist_expr; F->fold_signature_expr = copy_signature_expr; F->fold_block_stmt = copy_block_stmt; F->fold_expr_stmt = copy_expr_stmt; @@ -1252,12 +1537,18 @@ static void setup_copy_pass(AstFolder *F, Copier *C) F->fold_while_stmt = copy_while_stmt; F->fold_label_stmt = copy_label_stmt; F->fold_return_stmt = copy_return_stmt; + F->fold_variant_decl = copy_variant_decl; F->fold_var_decl = copy_var_decl; F->fold_func_decl = copy_func_decl; F->fold_struct_decl = copy_struct_decl; F->fold_field_decl = copy_field_decl; F->fold_generic_decl = copy_generic_decl; F->fold_type_decl = copy_type_decl; + F->fold_path_pat = copy_path_pat; + F->fold_tuple_pat = copy_tuple_pat; + F->fold_field_pat = copy_field_pat; + F->fold_struct_pat = copy_struct_pat; + F->fold_variant_pat = copy_variant_pat; } AstDecl *pawA_copy_decl(Ast *ast, AstDecl *decl) @@ -1374,27 +1665,34 @@ static void link_decls(AstFolder *F, AstDecl *old_decl, AstDecl *new_decl) } make_stencil_prep(expr, AstExpr, { - const DefId id = a_type(t)->hdr.def; - if (id != NO_DECL) { - AstDecl *old_decl = pawA_get_decl(F->ast, id); - AstDecl *new_decl = find_decl(F->state.S, old_decl); - r->hdr.type = a_type(new_decl); + Stenciler *S = F->state.S; + if (a_is_adt(t)) { + const DefId did = a_type(t)->adt.did; + AstDecl *decl = pawA_get_decl(F->ast, did); + r->hdr.type = a_type(find_decl(S, decl)); + } else if (a_is_fdef(t)) { + const DefId did = a_type(t)->func.did; + AstDecl *decl = pawA_get_decl(F->ast, did); + r->hdr.type = a_type(find_decl(S, decl)); } else { r->hdr.type = subst_type(F, a_type(t)); } }) - make_stencil_prep(decl, AstDecl, - { - r->hdr.name = t->hdr.name; - r->hdr.def = pawA_add_decl(F->ast, r); - link_decls(F, t, r); // subst_type() is dependant - AstType *type = subst_type(F, a_type(t)); - if (y_code(type) == NO_DECL) { - type->hdr.def = r->hdr.def; - } - r->hdr.type = type; - return r; - }) make_stencil_prep(stmt, AstStmt, {}) +make_stencil_prep(decl, AstDecl, + { + r->hdr.name = t->hdr.name; + r->hdr.def = pawA_add_decl(F->ast, r); + link_decls(F, t, r); // subst_type() is dependant + AstType *type = subst_type(F, a_type(t)); + if (a_is_func_decl(r)) { + type->func.did = r->hdr.def; + } else if (a_is_struct_decl(r)) { + type->adt.did = r->hdr.def; + } + r->hdr.type = type; + return r; + }) +make_stencil_prep(stmt, AstStmt, {}) //clang-format on // Helpers for stenciling: create a new node of the given type and kind, @@ -1413,10 +1711,11 @@ make_stencil_prep(expr, AstExpr, } \ return new_list; \ } - make_stencil_list(expr, AstExpr) make_stencil_list(decl, AstDecl) - make_stencil_list(stmt, AstStmt) +make_stencil_list(expr, AstExpr) +make_stencil_list(decl, AstDecl) +make_stencil_list(stmt, AstStmt) - static AstStmt *stencil_block_stmt(AstFolder *F, Block *s) +static AstStmt *stencil_block_stmt(AstFolder *F, Block *s) { ScopeState state; enter_scope(F, &state, s->scope); @@ -1486,15 +1785,6 @@ static AstExpr *stencil_chain_expr(AstFolder *F, ChainExpr *e) return r; } -static AstExpr *stencil_cond_expr(AstFolder *F, CondExpr *e) -{ - AstExpr *r = stencil_prep_expr(F, e); - r->cond.cond = F->fold_expr(F, e->cond); - r->cond.lhs = F->fold_expr(F, e->lhs); - r->cond.rhs = F->fold_expr(F, e->rhs); - return r; -} - static AstExpr *stencil_unop_expr(AstFolder *F, UnOpExpr *e) { AstExpr *r = stencil_prep_expr(F, e); @@ -1524,11 +1814,11 @@ static AstExpr *stencil_signature_expr(AstFolder *F, FuncType *e) { AstExpr *r = stencil_prep_expr(F, e); r->func.params = stencil_exprs(F, e->params); - r->func.return_ = F->fold_expr(F, e->return_); + r->func.result = F->fold_expr(F, e->result); return r; } -static AstExpr *stencil_type_name_expr(AstFolder *F, TypeName *e) +static AstExpr *stencil_typename_expr(AstFolder *F, TypeName *e) { AstExpr *r = stencil_prep_expr(F, e); r->type_name.name = e->name; @@ -1536,6 +1826,13 @@ static AstExpr *stencil_type_name_expr(AstFolder *F, TypeName *e) return r; } +static AstExpr *stencil_typelist_expr(AstFolder *F, TypeList *e) +{ + AstExpr *r = stencil_prep_expr(F, e); + r->typelist.types = stencil_exprs(F, e->types); + return r; +} + static AstDecl *stencil_field_decl(AstFolder *F, FieldDecl *d) { AstDecl *r = stencil_prep_decl(F, d); @@ -1560,6 +1857,19 @@ static AstDecl *stencil_generic_decl(AstFolder *F, GenericDecl *d) return r; } +static AstDecl *stencil_variant_decl(AstFolder *F, VariantDecl *d) +{ + AstDecl *r = stencil_prep_decl(F, d); + r->variant.name = d->name; + + ScopeState state; + enter_scope(F, &state, d->scope); + r->variant.fields = stencil_decls(F, d->fields); + r->variant.scope = leave_scope(F); + r->variant.index = d->index; + return r; +} + static AstDecl *stencil_struct_decl(AstFolder *F, StructDecl *d) { AstDecl *r = stencil_prep_decl(F, d); @@ -1568,6 +1878,7 @@ static AstDecl *stencil_struct_decl(AstFolder *F, StructDecl *d) enter_scope(F, &state, d->scope); r->struct_.is_global = d->is_global; + r->struct_.is_struct = d->is_struct; r->struct_.name = d->name; r->struct_.generics = stencil_decls(F, d->generics); @@ -1599,12 +1910,19 @@ static AstStmt *stencil_return_stmt(AstFolder *F, ReturnStmt *s) return r; } +static AstExpr *stencil_conversion_expr(AstFolder *F, ConversionExpr *e) +{ + AstExpr *r = stencil_prep_expr(F, e); + r->conv.to = e->to; + r->conv.arg = F->fold_expr(F, e->arg); + return r; +} + static AstExpr *stencil_call_expr(AstFolder *F, CallExpr *e) { AstExpr *r = stencil_prep_expr(F, e); - const DefId id = y_code(e->func); - if (id != NO_DECL) { - AstDecl *old_func = pawA_get_decl(F->ast, y_code(e->func)); + if (a_is_fdef(e->func)) { + AstDecl *old_func = pawA_get_decl(F->ast, e->func->func.did); AstDecl *new_func = find_decl(F->state.S, old_func); r->call.func = a_type(new_func); } else { @@ -1652,7 +1970,7 @@ static AstDecl *stencil_func_decl(AstFolder *F, FuncDecl *d) r->func.name = d->name; r->func.generics = stencil_decls(F, d->generics); r->func.params = stencil_decls(F, d->params); - r->func.return_ = F->fold_expr(F, d->return_); + r->func.result = F->fold_expr(F, d->result); r->func.body = stencil_block(F, d->body); r->func.fn_kind = d->fn_kind; @@ -1725,6 +2043,14 @@ static AstExpr *stencil_selector_expr(AstFolder *F, Selector *e) return r; } +static AstExpr *stencil_access_expr(AstFolder *F, Access *e) +{ + AstExpr *r = stencil_prep_expr(F, e); + r->access.target = F->fold_expr(F, e->target); + r->access.name = e->name; + return r; +} + static AstStmt *stencil_decl_stmt(AstFolder *F, AstDeclStmt *s) { AstStmt *r = stencil_prep_stmt(F, s); @@ -1732,6 +2058,36 @@ static AstStmt *stencil_decl_stmt(AstFolder *F, AstDeclStmt *s) return r; } +static AstPat *stencil_path_pat(AstFolder *V, AstPathPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *stencil_tuple_pat(AstFolder *V, AstTuplePat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *stencil_field_pat(AstFolder *V, AstFieldPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *stencil_struct_pat(AstFolder *V, AstStructPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + +static AstPat *stencil_variant_pat(AstFolder *V, AstVariantPat *p) +{ + paw_unused(V); + return cast_pat(p); +} + static void setup_stencil_pass(AstFolder *F, Stenciler *S) { const AstState state = {.S = S}; @@ -1742,12 +2098,14 @@ static void setup_stencil_pass(AstFolder *F, Stenciler *S) F->fold_chain_expr = stencil_chain_expr; F->fold_unop_expr = stencil_unop_expr; F->fold_binop_expr = stencil_binop_expr; - F->fold_cond_expr = stencil_cond_expr; + F->fold_conversion_expr = stencil_conversion_expr; F->fold_call_expr = stencil_call_expr; F->fold_index_expr = stencil_index_expr; + F->fold_access_expr = stencil_access_expr; F->fold_selector_expr = stencil_selector_expr; F->fold_item_expr = stencil_item_expr; - F->fold_type_name_expr = stencil_type_name_expr; + F->fold_typename_expr = stencil_typename_expr; + F->fold_typelist_expr = stencil_typelist_expr; F->fold_signature_expr = stencil_signature_expr; F->fold_block_stmt = stencil_block_stmt; F->fold_expr_stmt = stencil_expr_stmt; @@ -1757,6 +2115,7 @@ static void setup_stencil_pass(AstFolder *F, Stenciler *S) F->fold_while_stmt = stencil_while_stmt; F->fold_label_stmt = stencil_label_stmt; F->fold_return_stmt = stencil_return_stmt; + F->fold_variant_decl = stencil_variant_decl; F->fold_var_decl = stencil_var_decl; F->fold_func_decl = stencil_func_decl; F->fold_struct_decl = stencil_struct_decl; @@ -1764,6 +2123,11 @@ static void setup_stencil_pass(AstFolder *F, Stenciler *S) F->fold_generic_decl = stencil_generic_decl; F->fold_instance_decl = stencil_instance_decl; F->fold_type_decl = stencil_type_decl; + F->fold_path_pat = stencil_path_pat; + F->fold_tuple_pat = stencil_tuple_pat; + F->fold_field_pat = stencil_field_pat; + F->fold_struct_pat = stencil_struct_pat; + F->fold_variant_pat = stencil_variant_pat; } static AstList *prep_binder(AstTypeFolder *F, AstList *binder) @@ -1777,27 +2141,33 @@ static AstList *prep_binder(AstTypeFolder *F, AstList *binder) return copy; } -static AstType *prep_func(AstTypeFolder *F, AstFuncSig *t) +static AstType *prep_fptr(AstTypeFolder *F, AstFuncPtr *t) +{ + Subst *subst = F->state; + Stenciler *S = subst->S; + + AstType *r = pawA_new_type(S->ast, AST_TYPE_FPTR); + r->fptr.params = prep_binder(F, t->params); + r->fptr.result = F->fold(F, t->result); + return r; +} + +static AstType *prep_func(AstTypeFolder *F, AstFuncDef *t) { Subst *subst = F->state; Stenciler *S = subst->S; AstType *r = pawA_new_type(S->ast, AST_TYPE_FUNC); - if (t->def != NO_DECL) { - AstDecl *old_base = pawA_get_decl(S->ast, t->base); - AstDecl *new_base = find_decl(S, old_base); - AstDecl *old_decl = pawA_get_decl(S->ast, t->def); - AstDecl *new_decl = find_decl(S, old_decl); - r->func.def = new_decl->hdr.def; - r->func.base = new_base->hdr.def; - } else { - r->func.def = NO_DECL; - r->func.base = NO_DECL; - } + AstDecl *old_base = pawA_get_decl(S->ast, t->base); + AstDecl *new_base = find_decl(S, old_base); + AstDecl *old_decl = pawA_get_decl(S->ast, t->did); + AstDecl *new_decl = find_decl(S, old_decl); + r->func.did = new_decl->hdr.def; + r->func.base = new_base->hdr.def; r->func.types = prep_binder(F, t->types); r->func.params = prep_binder(F, t->params); - r->func.return_ = F->fold(F, t->return_); + r->func.result = F->fold(F, t->result); return r; } @@ -1805,12 +2175,15 @@ static AstType *prep_adt(AstTypeFolder *F, AstAdt *t) { Subst *subst = F->state; Stenciler *S = subst->S; + if (t->did <= PAW_TSTRING) { + return a_cast_type(t); + } AstDecl *old_base = pawA_get_decl(S->ast, t->base); AstDecl *new_base = find_decl(S, old_base); AstType *r = pawA_new_type(S->ast, AST_TYPE_ADT); - r->adt.def = new_base->hdr.def; + r->adt.did = new_base->hdr.def; r->adt.base = new_base->hdr.def; r->adt.types = prep_binder(F, t->types); return r; @@ -1879,6 +2252,7 @@ FuncDecl *pawA_stencil_func(Ast *ast, FuncDecl *base, AstDecl *inst) pawA_type_folder_init(&S.fold, &S); S.fold.fold_adt = prep_adt; + S.fold.fold_fptr = prep_fptr; S.fold.fold_func = prep_func; S.fold.fold_generic = prep_generic; @@ -1894,7 +2268,7 @@ FuncDecl *pawA_stencil_func(Ast *ast, FuncDecl *base, AstDecl *inst) inst->func.generics = copy.inst.types; add_symbol(&F, inst); // callee slot inst->func.params = stencil_decls(&F, base->params); - inst->func.return_ = F.fold_expr(&F, base->return_); + inst->func.result = F.fold_expr(&F, base->result); inst->func.body = stencil_block(&F, base->body); inst->func.fn_kind = base->fn_kind; @@ -1939,7 +2313,7 @@ static void dump_type_aux(Printer *P, AstType *type) }; switch (y_kind(type)) { case AST_TYPE_UNKNOWN: { - printf("?%d", type->unknown.def); + printf(""); break; } case AST_TYPE_GENERIC: { @@ -1958,7 +2332,7 @@ static void dump_type_aux(Printer *P, AstType *type) break; } case AST_TYPE_FUNC: { - AstFuncSig *func = &type->func; + AstFuncDef *func = &type->func; printf("%d", func->base); if (func->types->count > 0) { printf("["); @@ -1968,12 +2342,18 @@ static void dump_type_aux(Printer *P, AstType *type) printf("("); dump_binder(P, func->params); printf(") -> "); - dump_type_aux(P, func->return_); + dump_type_aux(P, func->result); break; } - default: - paw_assert(a_is_basic(type)); - printf("%s", basic[type->hdr.def]); + default: { + paw_assert(a_is_fptr(type)); + AstFuncPtr *fptr = &type->fptr; + printf("fn "); + printf("("); + dump_binder(P, fptr->params); + printf(") -> "); + dump_type_aux(P, fptr->result); + } } } @@ -2005,6 +2385,9 @@ static void print_decl_kind(Printer *P, void *node) case DECL_VAR: fprintf(P->out, "VarDecl"); break; + case DECL_VARIANT: + fprintf(P->out, "VariantDecl"); + break; case DECL_STRUCT: fprintf(P->out, "StructDecl"); break; @@ -2038,9 +2421,6 @@ static void print_expr_kind(Printer *P, void *node) case EXPR_CALL: fprintf(P->out, "CallExpr"); break; - case EXPR_COND: - fprintf(P->out, "CondExpr"); - break; case EXPR_NAME: fprintf(P->out, "Ident"); break; @@ -2053,12 +2433,18 @@ static void print_expr_kind(Printer *P, void *node) case EXPR_ACCESS: fprintf(P->out, "Access"); break; - case EXPR_FUNC_TYPE: + case EXPR_FUNCTYPE: fprintf(P->out, "FuncType"); break; - case EXPR_TYPE_NAME: + case EXPR_TYPENAME: fprintf(P->out, "TypeName"); break; + case EXPR_MATCH: + fprintf(P->out, "MatchExpr"); + break; + case EXPR_MATCHARM: + fprintf(P->out, "MatchArm"); + break; default: fprintf(P->out, "?"); break; @@ -2097,6 +2483,33 @@ static void print_stmt_kind(Printer *P, void *node) } } +static void print_pat_kind(Printer *P, void *node) +{ + AstPat *p = node; + switch (a_kind(p)) { + case AST_PAT_LITERAL: + fprintf(P->out, "LiteralPat"); + break; + case AST_PAT_PATH: + fprintf(P->out, "PathPat"); + break; + case AST_PAT_FIELD: + fprintf(P->out, "FieldPat"); + break; + case AST_PAT_TUPLE: + fprintf(P->out, "TuplePat"); + break; + case AST_PAT_VARIANT: + fprintf(P->out, "VariantPat"); + break; + case AST_PAT_STRUCT: + fprintf(P->out, "StructPat"); + break; + default: + fprintf(P->out, "?"); + } +} + static int predump_node(Printer *P, void *node, void (*print)(Printer *, void *)) { @@ -2115,6 +2528,7 @@ static int predump_node(Printer *P, void *node, static void dump_expr(Printer *P, AstExpr *e); static void dump_decl(Printer *P, AstDecl *d); static void dump_stmt(Printer *P, AstStmt *s); +static void dump_pat(Printer *P, AstPat *p); // clang-format off #define make_list_dumper(name, T) \ @@ -2135,6 +2549,7 @@ static void dump_stmt(Printer *P, AstStmt *s); make_list_dumper(expr, AstExpr) make_list_dumper(decl, AstDecl) make_list_dumper(stmt, AstStmt) +make_list_dumper(pat, AstPat) // clang-format on static void dump_decl(Printer *P, AstDecl *d) @@ -2153,8 +2568,8 @@ static void dump_decl(Printer *P, AstDecl *d) dump_fmt(P, "name: %s\n", d->func.name->text); dump_decl_list(P, d->func.generics, "generics"); dump_decl_list(P, d->func.params, "params"); - dump_msg(P, "return_: "); - dump_expr(P, d->func.return_); + dump_msg(P, "result: "); + dump_expr(P, d->func.result); dump_msg(P, "body: "); dump_block(P, d->func.body); dump_decl_list(P, d->func.monos, "monos"); @@ -2172,9 +2587,13 @@ static void dump_decl(Printer *P, AstDecl *d) dump_msg(P, "init: "); dump_expr(P, d->var.init); break; + case DECL_VARIANT: + dump_name(P, d->variant.name); + dump_decl_list(P, d->variant.fields, "fields"); + break; case DECL_STRUCT: dump_name(P, d->struct_.name); - dump_fmt(P, "type: %d\n", d->struct_.type->hdr.def); + dump_fmt(P, "is_struct: %d\n", d->struct_.is_struct); dump_decl_list(P, d->struct_.generics, "generics"); dump_decl_list(P, d->struct_.fields, "fields"); dump_decl_list(P, d->func.monos, "monos"); @@ -2270,6 +2689,42 @@ static void dump_stmt(Printer *P, AstStmt *s) dump_msg(P, "}\n"); } +static void dump_pat(Printer *P, AstPat *p) +{ + if (predump_node(P, p, print_pat_kind)) { + fprintf(P->out, "(null)\n"); + return; + } + ++P->indent; + dump_fmt(P, "line: %d\n", p->hdr.line); + switch (a_kind(p)) { + case AST_PAT_LITERAL: + dump_msg(P, "value: "); + dump_expr(P, p->literal.expr); + break; + case AST_PAT_PATH: + dump_msg(P, "path: \n"); // TODO: dump path + break; + case AST_PAT_FIELD: + dump_name(P, p->field.name); + dump_msg(P, "pat: "); + dump_pat(P, p->field.pat); + break; + case AST_PAT_TUPLE: + dump_pat_list(P, p->tuple.elems, "elems"); + break; + case AST_PAT_VARIANT: + dump_msg(P, "path: \n"); // TODO: dump path + dump_pat_list(P, p->variant.elems, "elems"); + break; + default: + paw_assert(a_kind(p) == AST_PAT_STRUCT); + break; + } + --P->indent; + dump_msg(P, "}\n"); +} + static void dump_expr(Printer *P, AstExpr *e) { if (predump_node(P, e, print_expr_kind)) { @@ -2330,14 +2785,6 @@ static void dump_expr(Printer *P, AstExpr *e) dump_expr(P, e->call.target); dump_expr_list(P, e->call.args, "args"); break; - case EXPR_COND: - dump_msg(P, "cond: "); - dump_expr(P, e->cond.cond); - dump_msg(P, "lhs: "); - dump_expr(P, e->cond.lhs); - dump_msg(P, "rhs: "); - dump_expr(P, e->cond.rhs); - break; case EXPR_NAME: dump_name(P, e->name.name); break; @@ -2351,15 +2798,25 @@ static void dump_expr(Printer *P, AstExpr *e) dump_expr(P, e->selector.target); dump_name(P, e->selector.name); break; - case EXPR_FUNC_TYPE: + case EXPR_FUNCTYPE: dump_expr_list(P, e->func.params, "params"); - dump_msg(P, "return_: "); - dump_expr(P, e->func.return_); + dump_msg(P, "result: "); + dump_expr(P, e->func.result); break; - case EXPR_TYPE_NAME: + case EXPR_TYPENAME: dump_name(P, e->type_name.name); dump_expr_list(P, e->type_name.args, "args"); break; + case EXPR_MATCH: + dump_msg(P, "target: "); + dump_expr(P, e->match.target); + dump_expr_list(P, e->match.arms, "arms"); + break; + case EXPR_MATCHARM: + dump_msg(P, "guard: "); + dump_pat(P, e->arm.guard); + dump_msg(P, "value: "); + dump_expr(P, e->arm.value); default: break; } @@ -2398,3 +2855,11 @@ void pawA_dump_stmt(FILE *out, AstStmt *stmt) P.indent = 0; dump_stmt(&P, stmt); } + +void pawA_dump_pat(FILE *out, AstPat *pat) +{ + Printer P; + P.out = out; + P.indent = 0; + dump_pat(&P, pat); +} diff --git a/src/ast.h b/src/ast.h index 66a3e58..88a88fd 100644 --- a/src/ast.h +++ b/src/ast.h @@ -13,6 +13,7 @@ typedef struct Ast Ast; typedef struct AstVisitor AstVisitor; typedef struct AstFolder AstFolder; typedef struct AstTypeFolder AstTypeFolder; +typedef struct AstPat AstPat; typedef struct AstType AstType; typedef struct AstDecl AstDecl; typedef struct AstExpr AstExpr; @@ -50,6 +51,7 @@ typedef struct VarInfo { Symbol *symbol; VarKind kind; int index; + int width; } VarInfo; //**************************************************************** @@ -67,22 +69,34 @@ AstList *pawA_list_new(Ast *ast); void pawA_list_free(Ast *ast, AstList *list); void pawA_list_push(Ast *ast, AstList **plist, void *node); +typedef struct AstPathSegment { + String *name; + AstList *types; +} AstPathSegment; + +void pawA_path_push(Ast *ast, AstList **ppath, String *name, AstList *types); + +static inline AstPathSegment *pawA_path_get(AstList *path, int index) +{ + paw_assert(index < path->count); + return path->data[index]; +} + //**************************************************************** // Types //**************************************************************** typedef enum AstTypeKind { // type->... - AST_TYPE_BASIC, // hdr AST_TYPE_GENERIC, // generic AST_TYPE_UNKNOWN, // unknown + AST_TYPE_TUPLE, // tuple AST_TYPE_ADT, // adt AST_TYPE_FUNC, // func + AST_TYPE_FPTR, // fptr AST_TYPE_MODULE, // mod } AstTypeKind; -#define AST_TYPE_HEADER \ - DefId def; \ - AstTypeKind kind : 8 +#define AST_TYPE_HEADER AstTypeKind kind : 8 typedef struct AstTypeHeader { AST_TYPE_HEADER; } AstTypeHeader; @@ -99,28 +113,33 @@ typedef struct AstUnknown { int index; } AstUnknown; -#define AST_POLY_HDR \ - AST_TYPE_HEADER; \ - AstList *types; \ - DefId base -typedef struct AstPolyHdr { - AST_POLY_HDR; -} AstPolyHdr; - -// Represents a function signature -// Note that the type variables for a function signature do not participate in -// unification (they are not part of the function type). -typedef struct AstFuncSig { - AST_POLY_HDR; // common initial sequence - AstList *params; // parameter types - AstType *return_; // return type -} AstFuncSig; - // Represents a structure or enumeration type typedef struct AstAdt { - AST_POLY_HDR; // common initial sequence + AST_TYPE_HEADER; // common initial sequence + AstList *types; + DefId base; + DefId did; } AstAdt; +#define AST_FUNC_HEADER AST_TYPE_HEADER; \ + AstList *params; \ + AstType *result +typedef struct AstFuncPtr { + AST_FUNC_HEADER; // common initial sequence +} AstFuncPtr; + +typedef struct AstFuncDef { + AST_FUNC_HEADER; // common initial sequence + AstList *types; + DefId base; + DefId did; +} AstFuncDef; + +typedef struct AstTupleType { + AST_TYPE_HEADER; // common initial sequence + AstList *elems; // element types +} AstTupleType; + // Represents the type of a Paw module // Note that basic types ('int', 'float', etc.) are created only once, at the // start of the root module's type vector. Included modules reference these @@ -136,31 +155,112 @@ typedef struct AstModule { struct AstType { union { AstTypeHeader hdr; - AstPolyHdr poly; AstGeneric generic; AstUnknown unknown; + AstTupleType tuple; AstAdt adt; - AstFuncSig func; + AstFuncPtr fptr; + AstFuncDef func; AstModule mod; }; }; #define a_cast_type(x) ((AstType *)(x)) -#define a_type_code(t) ((t)->hdr.def) +#define a_is_unit(t) (a_is_adt(t) && (t)->adt.did == PAW_TUNIT) +#define a_is_bool(t) (a_is_adt(t) && (t)->adt.did == PAW_TBOOL) +#define a_is_int(t) (a_is_adt(t) && (t)->adt.did == PAW_TINT) +#define a_is_float(t) (a_is_adt(t) && (t)->adt.did == PAW_TFLOAT) +#define a_is_string(t) (a_is_adt(t) && (t)->adt.did == PAW_TSTRING) +#define a_is_basic(t) (a_is_adt(t) && (t)->adt.did <= PAW_TSTRING) -#define a_is_unit(t) (a_is_basic(t) && a_type_code(t) == PAW_TUNIT) -#define a_is_bool(t) (a_is_basic(t) && a_type_code(t) == PAW_TBOOL) -#define a_is_int(t) (a_is_basic(t) && a_type_code(t) == PAW_TINT) -#define a_is_float(t) (a_is_basic(t) && a_type_code(t) == PAW_TFLOAT) -#define a_is_string(t) (a_is_basic(t) && a_type_code(t) == PAW_TSTRING) - -#define a_is_basic(t) (a_kind(t) == AST_TYPE_BASIC) #define a_is_generic(t) (a_kind(t) == AST_TYPE_GENERIC) #define a_is_unknown(t) (a_kind(t) == AST_TYPE_UNKNOWN) #define a_is_adt(t) (a_kind(t) == AST_TYPE_ADT) -#define a_is_func(t) (a_kind(t) == AST_TYPE_FUNC) +#define a_is_fdef(t) (a_kind(t) == AST_TYPE_FUNC) +#define a_is_fptr(t) (a_kind(t) == AST_TYPE_FPTR) +#define a_is_func(t) (a_is_fptr(t) || a_is_fdef(t)) +#define a_is_tuple(t) (a_kind(t) == AST_TYPE_TUPLE) #define a_is_module(t) (a_kind(t) == AST_TYPE_MODULE) +//**************************************************************** +// Pattern matching +//**************************************************************** + + +typedef enum AstPatKind { + AST_PAT_WILDCARD, + AST_PAT_BINDING, + AST_PAT_LITERAL, + AST_PAT_PATH, + AST_PAT_FIELD, + AST_PAT_TUPLE, + AST_PAT_STRUCT, + AST_PAT_VARIANT, +} AstPatKind; + +#define AST_PAT_HEADER AstType *type; \ + int line; \ + AstPatKind kind: 8 +typedef struct AstPatHdr { + AST_PAT_HEADER; // common fields +} AstPatHdr; + +typedef struct AstWildcardPat { + AST_PAT_HEADER; // common fields +} AstWildcardPat; + +typedef struct AstLiteralPat { + AST_PAT_HEADER; // common fields + AstExpr *expr; +} AstLiteralPat; + +typedef struct AstBindingPat { + AST_PAT_HEADER; // common fields + String *name; +} AstBindingPat; + +typedef struct AstPathPat { + AST_PAT_HEADER; // common fields + AstList *path; +} AstPathPat; + +typedef struct AstTuplePat { + AST_PAT_HEADER; // common fields + AstList *elems; // list of AstPat +} AstTuplePat; + +typedef struct AstStructPat { + AST_PAT_HEADER; // common fields + AstList *path; // path to structure + AstList *fields; // list of AstPat +} AstStructPat; + +typedef struct AstVariantPat { + AST_PAT_HEADER; // common fields + AstList *path; // path to variant + AstList *elems; // list of AstPat +} AstVariantPat; + +typedef struct AstFieldPat { + AST_PAT_HEADER; // common fields + String *name; // name of field + AstPat *pat; +} AstFieldPat; + +struct AstPat { + union { + AstPatHdr hdr; + AstWildcardPat wildcard; + AstLiteralPat literal; + AstBindingPat binding; + AstPathPat path; + AstTuplePat tuple; + AstFieldPat field; + AstStructPat struct_; + AstVariantPat variant; + }; +}; + //**************************************************************** // Declarations //**************************************************************** @@ -172,6 +272,7 @@ typedef enum AstDeclKind { DECL_STRUCT, DECL_FIELD, DECL_GENERIC, + DECL_VARIANT, DECL_INSTANCE, } AstDeclKind; @@ -210,18 +311,20 @@ typedef struct FuncDecl { Scope *scope; // function-scoped symbols, including generics AstList *generics; // generic type parameters (FieldDecl) AstList *params; // parameter declarations - AstExpr *return_; // return type + AstExpr *result; // return type Block *body; // function body AstList *monos; // list of monomorphizations } FuncDecl; -// TODO: Need to prevent recursive structures, or introduce the concept of -// indirection (otherwise, structs that +// TODO: Call this AdtDecl? +// Need to prevent recursive structures, or introduce the concept of +// indirection (otherwise, structs that // contain an instance of themselves as a field will become infinitely // large)... typedef struct StructDecl { DECL_HEADER; // common initial sequence paw_Bool is_global : 1; // uses 'global' keyword + paw_Bool is_struct : 1; // 'struct' vs. 'enum' Scope *scope; // scope for struct-level symbols Scope *field_scope; AstList *fields; // list of FieldDecl @@ -230,6 +333,13 @@ typedef struct StructDecl { int location; } StructDecl; +typedef struct VariantDecl { + DECL_HEADER; // common initial sequence + Scope *scope; + AstList *fields; + int index; +} VariantDecl; + // Represents a template instance // Created when an instantiation is found of the template that is currently // being visited. For function templates, this node just stores the type of @@ -262,6 +372,7 @@ typedef struct AstDecl { FuncDecl func; StructDecl struct_; InstanceDecl inst; + VariantDecl variant; FieldDecl field; GenericDecl generic; TypeDecl type; @@ -281,17 +392,18 @@ typedef enum AstExprKind { EXPR_CHAIN, EXPR_UNOP, EXPR_BINOP, - EXPR_COALESCE, EXPR_LOGICAL, - EXPR_COND, EXPR_INDEX, EXPR_ACCESS, + EXPR_CONVERSION, EXPR_SELECTOR, EXPR_INVOKE, - EXPR_SYMBOL, EXPR_ITEM, - EXPR_FUNC_TYPE, - EXPR_TYPE_NAME, + EXPR_MATCH, + EXPR_MATCHARM, + EXPR_FUNCTYPE, + EXPR_TYPENAME, + EXPR_TYPELIST, } AstExprKind; #define EXPR_HEADER \ @@ -365,13 +477,6 @@ typedef struct BinOpExpr { AstExpr *rhs; } BinOpExpr; -typedef struct CondExpr { - EXPR_HEADER; - AstExpr *cond; - AstExpr *lhs; - AstExpr *rhs; -} CondExpr; - typedef struct LogicalExpr { EXPR_HEADER; paw_Bool is_and : 1; @@ -398,7 +503,11 @@ typedef struct CallExpr { typedef struct Selector { SUFFIXED_HEADER; // common fields - String *name; // name of the field + paw_Bool is_index: 1; + union { + String *name; + paw_Int index; + }; } Selector; typedef struct Access { @@ -411,6 +520,17 @@ typedef struct Index { AstList *elems; // list of elements } Index; +typedef struct ConversionExpr { + EXPR_HEADER; + paw_Type to; + AstExpr *arg; +} ConversionExpr; + +typedef struct TypeList { + EXPR_HEADER; + AstList *types; +} TypeList; + // A valid TypeName is related to a AstDecl through the symbol table. typedef struct TypeName { EXPR_HEADER; // common initial sequence @@ -420,10 +540,24 @@ typedef struct TypeName { typedef struct FuncType { EXPR_HEADER; // common initial sequence - AstExpr *return_; // return type annotation + AstExpr *result; // return type annotation AstList *params; // parameter types } FuncType; +typedef struct MatchArm { + EXPR_HEADER; + Scope *scope; + AstPat *guard; + AstExpr *cond; + AstExpr *value; +} MatchArm; + +typedef struct MatchExpr { + EXPR_HEADER; + AstExpr *target; + AstList *arms; +} MatchExpr; + typedef struct AstExpr { union { AstExprHeader hdr; @@ -433,15 +567,18 @@ typedef struct AstExpr { ChainExpr chain; UnOpExpr unop; BinOpExpr binop; - CondExpr cond; + ConversionExpr conv; SuffixedExpr suffix; CallExpr call; Index index; Access access; Selector selector; + TypeList typelist; ItemExpr item; TypeName type_name; FuncType func; + MatchExpr match; + MatchArm arm; }; } AstExpr; @@ -561,6 +698,7 @@ typedef union AstState { typedef void (*AstExprPass)(AstVisitor *pass, AstExpr *e); typedef void (*AstStmtPass)(AstVisitor *pass, AstStmt *s); typedef void (*AstDeclPass)(AstVisitor *pass, AstDecl *d); +typedef void (*AstPatPass)(AstVisitor *pass, AstPat *p); // Represents a single pass over an AST struct AstVisitor { @@ -571,6 +709,7 @@ struct AstVisitor { AstExprPass visit_expr; AstStmtPass visit_stmt; AstDeclPass visit_decl; + AstPatPass visit_pat; void (*visit_expr_list)(AstVisitor *V, AstList *list, AstExprPass cb); void (*visit_decl_list)(AstVisitor *V, AstList *list, AstDeclPass cb); @@ -582,15 +721,18 @@ struct AstVisitor { void (*visit_chain_expr)(AstVisitor *V, ChainExpr *e); void (*visit_unop_expr)(AstVisitor *V, UnOpExpr *e); void (*visit_binop_expr)(AstVisitor *V, BinOpExpr *e); - void (*visit_cond_expr)(AstVisitor *V, CondExpr *e); void (*visit_suffix_expr)(AstVisitor *V, SuffixedExpr *e); + void (*visit_conversion_expr)(AstVisitor *V, ConversionExpr *e); void (*visit_call_expr)(AstVisitor *V, CallExpr *e); void (*visit_index_expr)(AstVisitor *V, Index *e); void (*visit_access_expr)(AstVisitor *V, Access *e); void (*visit_selector_expr)(AstVisitor *V, Selector *e); void (*visit_item_expr)(AstVisitor *V, ItemExpr *e); - void (*visit_type_name_expr)(AstVisitor *V, TypeName *e); + void (*visit_typelist_expr)(AstVisitor *V, TypeList *e); + void (*visit_typename_expr)(AstVisitor *V, TypeName *e); void (*visit_signature_expr)(AstVisitor *V, FuncType *e); + void (*visit_match_expr)(AstVisitor *V, MatchExpr *e); + void (*visit_arm_expr)(AstVisitor *V, MatchArm *e); void (*visit_block_stmt)(AstVisitor *V, Block *s); void (*visit_expr_stmt)(AstVisitor *V, AstExprStmt *s); @@ -609,6 +751,14 @@ struct AstVisitor { void (*visit_generic_decl)(AstVisitor *V, GenericDecl *d); void (*visit_type_decl)(AstVisitor *V, TypeDecl *d); void (*visit_instance_decl)(AstVisitor *V, InstanceDecl *d); + void (*visit_variant_decl)(AstVisitor *V, VariantDecl *d); + + void (*visit_literal_pat)(AstVisitor *V, AstLiteralPat *p); + void (*visit_path_pat)(AstVisitor *V, AstPathPat *p); + void (*visit_tuple_pat)(AstVisitor *V, AstTuplePat *p); + void (*visit_field_pat)(AstVisitor *V, AstFieldPat *p); + void (*visit_struct_pat)(AstVisitor *V, AstStructPat *p); + void (*visit_variant_pat)(AstVisitor *V, AstVariantPat *p); }; void pawA_visitor_init(AstVisitor *V, Ast *ast, AstState state); @@ -617,6 +767,7 @@ void pawA_visit(AstVisitor *V); typedef AstExpr *(*AstExprFold)(AstFolder *F, AstExpr *e); typedef AstStmt *(*AstStmtFold)(AstFolder *F, AstStmt *s); typedef AstDecl *(*AstDeclFold)(AstFolder *F, AstDecl *d); +typedef AstPat *(*AstPatFold)(AstFolder *F, AstPat *p); struct AstFolder { AstState state; @@ -626,6 +777,7 @@ struct AstFolder { AstExprFold fold_expr; AstStmtFold fold_stmt; AstDeclFold fold_decl; + AstPatFold fold_pat; void (*fold_expr_list)(AstFolder *F, AstList *list, AstExprFold cb); void (*fold_decl_list)(AstFolder *F, AstList *list, AstDeclFold cb); @@ -637,15 +789,18 @@ struct AstFolder { AstExpr *(*fold_chain_expr)(AstFolder *F, ChainExpr *e); AstExpr *(*fold_unop_expr)(AstFolder *F, UnOpExpr *e); AstExpr *(*fold_binop_expr)(AstFolder *F, BinOpExpr *e); - AstExpr *(*fold_cond_expr)(AstFolder *F, CondExpr *e); AstExpr *(*fold_suffix_expr)(AstFolder *F, SuffixedExpr *e); + AstExpr *(*fold_conversion_expr)(AstFolder *F, ConversionExpr *e); AstExpr *(*fold_call_expr)(AstFolder *F, CallExpr *e); AstExpr *(*fold_index_expr)(AstFolder *F, Index *e); AstExpr *(*fold_access_expr)(AstFolder *F, Access *e); AstExpr *(*fold_selector_expr)(AstFolder *F, Selector *e); AstExpr *(*fold_item_expr)(AstFolder *F, ItemExpr *e); - AstExpr *(*fold_type_name_expr)(AstFolder *F, TypeName *e); + AstExpr *(*fold_typename_expr)(AstFolder *F, TypeName *e); + AstExpr *(*fold_typelist_expr)(AstFolder *F, TypeList *e); AstExpr *(*fold_signature_expr)(AstFolder *F, FuncType *e); + AstExpr *(*fold_match_expr)(AstFolder *F, MatchExpr *e); + AstExpr *(*fold_arm_expr)(AstFolder *F, MatchArm *e); AstStmt *(*fold_block_stmt)(AstFolder *F, Block *s); AstStmt *(*fold_expr_stmt)(AstFolder *F, AstExprStmt *s); @@ -663,6 +818,14 @@ struct AstFolder { AstDecl *(*fold_generic_decl)(AstFolder *F, GenericDecl *d); AstDecl *(*fold_type_decl)(AstFolder *F, TypeDecl *d); AstDecl *(*fold_instance_decl)(AstFolder *F, InstanceDecl *d); + AstDecl *(*fold_variant_decl)(AstFolder *F, VariantDecl *d); + + AstPat *(*fold_literal_pat)(AstFolder *F, AstLiteralPat *p); + AstPat *(*fold_path_pat)(AstFolder *F, AstPathPat *p); + AstPat *(*fold_tuple_pat)(AstFolder *F, AstTuplePat *p); + AstPat *(*fold_field_pat)(AstFolder *F, AstFieldPat *p); + AstPat *(*fold_struct_pat)(AstFolder *F, AstStructPat *p); + AstPat *(*fold_variant_pat)(AstFolder *F, AstVariantPat *p); }; void pawA_folder_init(AstFolder *F, Ast *ast, AstState state); @@ -673,7 +836,8 @@ struct AstTypeFolder { AstType *(*fold)(AstTypeFolder *F, AstType *type); AstType *(*fold_basic)(AstTypeFolder *F, AstTypeHeader *t); - AstType *(*fold_func)(AstTypeFolder *F, AstFuncSig *t); + AstType *(*fold_fptr)(AstTypeFolder *F, AstFuncPtr *t); + AstType *(*fold_func)(AstTypeFolder *F, AstFuncDef *t); AstType *(*fold_adt)(AstTypeFolder *F, AstAdt *t); AstType *(*fold_unknown)(AstTypeFolder *F, AstUnknown *t); AstType *(*fold_generic)(AstTypeFolder *F, AstGeneric *t); @@ -700,6 +864,7 @@ typedef struct Ast { //**************************************************************** Symbol *pawA_new_symbol(Lex *lex); +AstPat *pawA_new_pat(Ast *ast, AstPatKind kind); AstType *pawA_new_type(Ast *ast, AstTypeKind kind); AstDecl *pawA_new_decl(Ast *ast, AstDeclKind kind); AstExpr *pawA_new_expr(Ast *ast, AstExprKind kind); @@ -713,6 +878,7 @@ void *pawA_new_pointer_vec(Ast *ast, int nptrs); #define cast_decl(x) ((AstDecl *)(x)) #define cast_expr(x) ((AstExpr *)(x)) #define cast_stmt(x) ((AstStmt *)(x)) +#define cast_pat(x) ((AstPat *)(x)) //**************************************************************** // AST manipulation @@ -737,7 +903,7 @@ AstDecl *pawA_get_decl(Ast *ast, DefId id); // Macros for checking node types #define a_is_generic_type(e) (a_kind(e) == EXPR_GENERIC_TYPE) -#define a_is_named_type(e) (a_kind(e) == EXPR_TYPE_NAME) +#define a_is_named_type(e) (a_kind(e) == EXPR_TYPENAME) #define a_is_func_type(e) (a_kind(e) == EXPR_FUNC_TYPE) #define a_is_generic_decl(e) (a_kind(e) == DECL_GENERIC) #define a_is_struct_decl(d) (a_kind(d) == DECL_STRUCT) @@ -752,9 +918,12 @@ AstDecl *pawA_get_decl(Ast *ast, DefId id); #define a_is_struct_template_decl(d) \ (a_is_struct_decl(d) && (d)->struct_.generics->count > 0) +#define a_adt_id(t) check_exp(a_is_adt(t), (t)->adt.base - PAW_TSTRING) + void pawA_dump_type(FILE *out, AstType *type); void pawA_dump_decl(FILE *out, AstDecl *decl); void pawA_dump_expr(FILE *out, AstExpr *expr); void pawA_dump_stmt(FILE *out, AstStmt *stmt); +void pawA_dump_pat(FILE *out, AstPat *pat); #endif // PAW_AST_H diff --git a/src/auxlib.c b/src/auxlib.c index 35c5fdb..cbac056 100644 --- a/src/auxlib.c +++ b/src/auxlib.c @@ -187,7 +187,7 @@ void pawL_add_vfstring(paw_Env *P, Buffer *buf, const char *fmt, va_list arg) pawL_add_integer(P, buf, va_arg(arg, int64_t)); break; case 'c': - pawL_add_char(P, buf, *fmt); + pawL_add_char(P, buf, va_arg(arg, int)); break; case 'f': pawL_add_float(P, buf, va_arg(arg, double)); diff --git a/src/check.c b/src/check.c index 25a27d7..47825be 100644 --- a/src/check.c +++ b/src/check.c @@ -13,6 +13,7 @@ #include "gc_aux.h" #include "map.h" #include "mem.h" +#include "parse.h" #include "str.h" #include "type.h" #include "unify.h" @@ -21,7 +22,7 @@ // Helper macros #define syntax_error(R, ...) pawX_error((R)->lex, __VA_ARGS__) #define type_error(R, ...) pawX_error((R)->lex, __VA_ARGS__) -#define resolve_expr(V, e) ((V)->visit_expr(V, e), a_type(e)) +#define resolve_pat(V, p) ((V)->visit_pat(V, p), a_type(p)) #define cached_str(R, i) pawE_cstr(env((R)->lex), cast_size(i)) #define basic_decl(R, code) basic_symbol(R, code)->decl #define is_unit(e) (type2code(e) == PAW_TUNIT) @@ -34,30 +35,34 @@ // Common state for type-checking routines typedef struct Resolver { Lex *lex; // lexical state - StructDecl *struct_; // enclosing struct declaration - AstType *return_; // enclosing function return type + AstType *adt; // enclosing ADT + AstType *result; // enclosing function return type SymbolTable *sym; // scoped symbol table Ast *ast; // AST being checked ParseMemory *pm; // dynamic memory Unifier *U; // unification tables - GenericState *gs; // generic context + GenericState *gs; // info about current generic parameters + struct MatchState *ms; // info about current match expression int func_depth; // number of nested functions + int option_did; + int result_did; } Resolver; -static AstType *get_type(Resolver *R, DefId id) +static AstType *get_type(Resolver *R, DefId did) { - paw_assert(id < R->pm->decls.size); - return a_type(R->pm->decls.data[id]); + paw_assert(did < R->pm->decls.size); + return a_type(R->pm->decls.data[did]); } static paw_Type type2code(AstType *type) { - if (a_is_basic(type)) { - return type->hdr.def; - } else if (a_is_adt(type)) { - return type->adt.base; - } - return -1; + return a_is_adt(type) ? type->adt.base : -1; +} + +static AstType *resolve_expr(AstVisitor *V, AstExpr *e) +{ + V->visit_expr(V, e); + return a_type(e); } #define are_types_same(a, b) ((a) == (b)) @@ -80,13 +85,16 @@ static paw_Bool test_types(Resolver *R, const AstType *a, const AstType *b) return PAW_FALSE; } switch (a_kind(a)) { + case AST_TYPE_TUPLE: + return test_binders(R, a->tuple.elems, b->tuple.elems); + case AST_TYPE_FPTR: + return test_binders(R, a->fptr.params, b->fptr.params); case AST_TYPE_FUNC: - return test_binders(R, a->func.params, b->func.params); + return test_types(R, a->func.result, b->func.result) && + test_binders(R, a->func.params, b->func.params); case AST_TYPE_ADT: { - if (a->adt.base != b->adt.base) { - return PAW_FALSE; - } - return test_binders(R, a->adt.types, b->adt.types); + return a->adt.base == b->adt.base && + test_binders(R, a->adt.types, b->adt.types); } default: return are_types_same(a, b); @@ -102,7 +110,10 @@ static Symbol *basic_symbol(Resolver *R, paw_Type code) return toplevel->symbols[1 + code]; // TODO } -static void push_symbol_table(Resolver *R) { pawP_new_scope(R->lex, R->sym); } +static void push_symbol_table(Resolver *R) +{ + pawP_new_scope(R->lex, R->sym); +} static void pop_symbol_table(Resolver *R) { @@ -118,21 +129,27 @@ static DefId add_decl(Resolver *R, AstDecl *decl) return pawA_add_decl(R->ast, decl); } -static AstDecl *get_decl(Resolver *R, DefId id) +static AstDecl *get_decl(Resolver *R, DefId did) { ParseMemory *pm = R->pm; - paw_assert(id < pm->decls.size); - return pm->decls.data[id]; + paw_assert(did < pm->decls.size); + return pm->decls.data[did]; } -static AstType *new_type(Resolver *R, DefId id, AstTypeKind kind) +static AstType *new_type(Resolver *R, DefId did, AstTypeKind kind) { AstType *type = pawA_new_type(R->ast, kind); - type->hdr.def = id; - if (id != NO_DECL) { + if (did != NO_DECL) { // set type of associated definition - AstDecl *d = get_decl(R, id); + AstDecl *d = get_decl(R, did); d->hdr.type = type; + if (kind == AST_TYPE_ADT) { + type->adt.types = pawA_list_new(R->ast); + type->adt.did = did; + } else { + type->func.types = pawA_list_new(R->ast); + type->func.did = did; + } } return type; } @@ -164,8 +181,8 @@ static AstType *param_collector2(AstVisitor *V, AstDecl *decl) static AstType *generic_collector(AstVisitor *V, AstDecl *decl) { GenericDecl *d = &decl->generic; - DefId id = add_decl(V->state.R, decl); - d->type = new_type(V->state.R, id, AST_TYPE_GENERIC); + DefId did = add_decl(V->state.R, decl); + d->type = new_type(V->state.R, did, AST_TYPE_GENERIC); d->type->generic.name = d->name; return d->type; } @@ -235,7 +252,7 @@ static Symbol *add_global(Resolver *R, String *name, AstDecl *decl) return add_symbol(R, st, name, decl); } -static Symbol *resolve_symbol(Resolver *R, String *name) +static Symbol *try_resolve_symbol(Resolver *R, String *name) { // search the scoped symbols SymbolTable *scopes = R->sym; @@ -249,11 +266,20 @@ static Symbol *resolve_symbol(Resolver *R, String *name) // search the global symbols const int index = pawP_find_symbol(scopes->globals, name); if (index < 0) { - syntax_error(R, "undefined symbol '%s'", name->text); + return NULL; } return scopes->globals->symbols[index]; } +static Symbol *resolve_symbol(Resolver *R, String *name) +{ + Symbol *symbol = try_resolve_symbol(R, name); + if (symbol == NULL) { + syntax_error(R, "undefined symbol '%s'", name->text); + } + return symbol; +} + static AstDecl *resolve_attr(AstList *attrs, String *name) { for (int i = 0; i < attrs->count; ++i) { @@ -313,12 +339,11 @@ static Scope *leave_function(Resolver *R) return scope; } -static void enter_function(Resolver *R, String *name, Scope *scope, - FuncDecl *func) +static void enter_function(Resolver *R, Scope *scope, FuncDecl *func) { ++R->func_depth; enter_block(R, scope); - new_local(R, name, cast_decl(func)); + new_local(R, func->name, cast_decl(func)); } static void new_local_literal(Resolver *R, const char *name, paw_Type code) @@ -366,15 +391,25 @@ static AstList *prep_binder(AstTypeFolder *F, AstList *binder) return copy; } -static AstType *prep_func(AstTypeFolder *F, AstFuncSig *t) +static AstType *prep_fptr(AstTypeFolder *F, AstFuncPtr *t) { Subst *subst = F->state; Resolver *R = subst->R; - AstType *r = pawA_new_type(R->ast, AST_TYPE_FUNC); - r->func.base = t->def; + AstType *r = new_type(R, NO_DECL, AST_TYPE_FPTR); + r->fptr.params = prep_binder(F, t->params); + r->fptr.result = F->fold(F, t->result); + return r; +} + +static AstType *prep_func(AstTypeFolder *F, AstFuncDef *t) +{ + Subst *subst = F->state; + Resolver *R = subst->R; + AstType *r = new_type(R, NO_DECL, AST_TYPE_FUNC); // TODO: did + r->func.base = t->did; r->func.types = prep_binder(F, t->types); r->func.params = prep_binder(F, t->params); - r->func.return_ = F->fold(F, t->return_); + r->func.result = F->fold(F, t->result); return r; } @@ -382,7 +417,10 @@ static AstType *prep_adt(AstTypeFolder *F, AstAdt *t) { Subst *subst = F->state; Resolver *R = subst->R; - AstType *r = pawA_new_type(R->ast, AST_TYPE_ADT); + if (t->did <= PAW_TSTRING) { + return a_cast_type(t); + } + AstType *r = new_type(R, NO_DECL, AST_TYPE_ADT); // TODO: did r->adt.base = t->base; r->adt.types = prep_binder(F, t->types); return r; @@ -412,7 +450,7 @@ static AstType *prep_unknown(AstTypeFolder *F, AstUnknown *t) // Make a copy of a function template's parameter list, with bound (by the // template) type variables replaced with inference variables. The types // returned by this function can be unified with the type of each argument -// passed at the call site to determine a concrete type for each type variable. +// passed at the call site to determine a concrete type for each unknown. static AstList *prep_inference(AstVisitor *V, AstList *generics, AstList *after, AstList *params) { @@ -428,6 +466,7 @@ static AstList *prep_inference(AstVisitor *V, AstList *generics, AstList *after, AstTypeFolder F; pawA_type_folder_init(&F, &subst); F.fold_adt = prep_adt; + F.fold_fptr = prep_fptr; F.fold_func = prep_func; F.fold_generic = prep_generic; F.fold_unknown = prep_unknown; @@ -439,8 +478,8 @@ static AstType *register_decl_type(AstVisitor *V, AstDecl *decl, AstTypeKind kind) { Resolver *R = V->state.R; - DefId id = add_decl(V->state.R, decl); - AstType *r = new_type(R, id, kind); + DefId did = add_decl(V->state.R, decl); + AstType *r = new_type(R, did, kind); decl->hdr.type = r; return r; } @@ -468,7 +507,7 @@ static void register_base_func(AstVisitor *V, FuncDecl *d) AstType *r = register_decl_type(V, cast_decl(d), AST_TYPE_FUNC); r->func.types = register_generics(V, d->generics); r->func.params = collect_params(V, d->params); - r->func.return_ = resolve_expr(V, d->return_); + r->func.result = resolve_expr(V, d->result); r->func.base = d->def; d->type = r; @@ -493,11 +532,6 @@ static void decl_callback(AstVisitor *V, AstDecl *decl) add_decl(V->state.R, decl); } -static AstList *new_concrete_types(AstVisitor *V, AstList *list) -{ - return transfer_fields(V, list, decl_callback); -} - static void register_func_instance(AstVisitor *V, FuncDecl *base, InstanceDecl *inst, AstList *types) { @@ -505,32 +539,74 @@ static void register_func_instance(AstVisitor *V, FuncDecl *base, enter_block(R, NULL); inst->name = base->name; - inst->types = new_concrete_types(V, base->generics); + inst->types = transfer_fields(V, base->generics, decl_callback); register_concrete_types(V, inst->types, types); AstType *r = register_decl_type(V, cast_decl(inst), AST_TYPE_FUNC); r->func.base = base->def; r->func.params = collect_params2(V, base->params); - r->func.return_ = resolve_expr(V, base->return_); + r->func.result = resolve_expr(V, base->result); r->func.types = types; inst->type = r; inst->scope = leave_block(R); } +static Scope *collect_fields(AstVisitor *V, AstList *list) +{ + Resolver *R = V->state.R; + enter_block(R, NULL); + + for (int i = 0; i < list->count; ++i) { + AstDecl *decl = list->data[i]; + V->visit_decl(V, decl); + new_local(R, NULL, decl); + } + return leave_block(R); +} + +// TODO: Use this +static void visit_variant_decl(AstVisitor *V, VariantDecl *d) +{ + Resolver *R = V->state.R; + add_decl(V->state.R, cast_decl(d)); + + // An enum variant name can be thought of as a function from the type of the variant's + // fields to the type of the enumeration. For example, given 'enum E {X(string)}', + // E::X has type 'fn(string) -> E'. + d->type = new_type(R, d->def, AST_TYPE_FUNC); + d->type->func.base = R->adt->adt.did; + d->type->func.types = pawA_list_new(V->ast); + d->type->func.params = collect_params(V, d->fields); + d->type->func.result = R->adt; + + new_local(R, d->name, cast_decl(d)); + d->scope = collect_fields(V, d->fields); +} + static void register_field_decl(AstVisitor *V, AstDecl *decl) { + Resolver *R = V->state.R; add_decl(V->state.R, decl); - FieldDecl *d = &decl->field; - new_local(V->state.R, d->name, decl); - d->type = resolve_expr(V, d->tag); + if (a_kind(decl) == DECL_VARIANT) { + VariantDecl *d = &decl->variant; + d->scope = collect_fields(V, d->fields); + d->type = new_type(R, d->def, AST_TYPE_FUNC); + d->type->func.base = R->adt->adt.did; + d->type->func.types = pawA_list_new(V->ast); + d->type->func.params = collect_params(V, d->fields); + d->type->func.result = R->adt; + } else { + paw_assert(a_kind(decl) == DECL_FIELD); + FieldDecl *d = &decl->field; + d->type = resolve_expr(V, d->tag); + } + new_local(R, decl->hdr.name, decl); } static void register_base_struct(AstVisitor *V, StructDecl *d) { Resolver *R = V->state.R; - StructDecl *enclosing = R->struct_; - R->struct_ = d; // enter struct context enter_block(R, NULL); AstType *r = register_decl_type(V, cast_decl(d), AST_TYPE_ADT); @@ -538,12 +614,15 @@ static void register_base_struct(AstVisitor *V, StructDecl *d) r->adt.base = d->def; d->type = r; + AstType *enclosing = R->adt; + R->adt = r; + enter_block(R, NULL); V->visit_decl_list(V, d->fields, register_field_decl); d->field_scope = leave_block(R); d->scope = leave_block(R); - R->struct_ = enclosing; + R->adt = enclosing; } static void register_struct_instance(AstVisitor *V, StructDecl *base, @@ -553,7 +632,7 @@ static void register_struct_instance(AstVisitor *V, StructDecl *base, enter_block(R, NULL); inst->name = base->name; - inst->types = new_concrete_types(V, base->generics); + inst->types = transfer_fields(V, base->generics, decl_callback); register_concrete_types(V, inst->types, types); AstType *r = register_decl_type(V, cast_decl(inst), AST_TYPE_ADT); @@ -561,22 +640,15 @@ static void register_struct_instance(AstVisitor *V, StructDecl *base, r->adt.types = types; inst->type = r; + AstType *enclosing = R->adt; + R->adt = inst->type; + enter_block(R, NULL); inst->fields = transfer_fields(V, base->fields, register_field_decl); inst->field_scope = leave_block(R); inst->scope = leave_block(R); -} - -static AstList *get_monos(AstDecl *base) -{ - switch (a_kind(base)) { - case DECL_FUNC: - return base->func.monos; - default: - paw_assert(a_kind(base) == DECL_STRUCT); - return base->struct_.monos; - } + R->adt = enclosing; } static AstDecl *find_func_instance(AstVisitor *V, FuncDecl *base, @@ -585,7 +657,7 @@ static AstDecl *find_func_instance(AstVisitor *V, FuncDecl *base, Resolver *R = V->state.R; for (int i = 0; i < base->monos->count; ++i) { AstDecl *inst = base->monos->data[i]; - const AstType *type = get_type(R, inst->hdr.def); + const AstType *type = get_type(R, inst->inst.def); if (test_binders(R, types, type->func.types)) { return inst; } @@ -600,8 +672,8 @@ static AstDecl *find_struct_instance(AstVisitor *V, StructDecl *base, Resolver *R = V->state.R; for (int i = 0; i < base->monos->count; ++i) { AstDecl *inst = base->monos->data[i]; - const AstType *type = get_type(R, inst->hdr.def); - if (test_binders(R, types, type->func.types)) { + const AstType *type = get_type(R, inst->inst.def); + if (test_binders(R, types, type->adt.types)) { return inst; } inst = inst->hdr.next; @@ -624,21 +696,21 @@ static void visit_func(AstVisitor *V, FuncDecl *d, FuncKind kind) AstType *type = get_type(R, d->def); d->fn_kind = kind; - enter_function(R, d->name, d->scope, d); + enter_function(R, d->scope, d); V->visit_decl_list(V, d->params, visit_param_decl); - AstType *outer = R->return_; - R->return_ = type->func.return_; + AstType *outer = R->result; + R->result = type->func.result; V->visit_block_stmt(V, d->body); d->scope = leave_function(R); - R->return_ = outer; + R->result = outer; } static void visit_return_stmt(AstVisitor *V, ReturnStmt *s) { Resolver *R = V->state.R; - AstType *want = R->return_; // function return type + AstType *want = R->result; // function return type AstType *have = s->expr ? resolve_expr(V, s->expr) : NULL; if (a_is_unit(want)) { @@ -716,26 +788,79 @@ static void expect_int_expr(AstVisitor *V, AstExpr *e) unify(R, type, get_type(R, PAW_TINT)); } -static void visit_type_name_expr(AstVisitor *V, TypeName *e) +static AstType *instantiate(AstVisitor *V, AstDecl *base, AstList *types) +{ + if (a_is_struct_template_decl(base)) { + StructDecl *d = &base->struct_; + types = collect_expr_types(V, types); + return init_struct_template(V, d, types); + } + return a_type(base); +} + +static void visit_typename_expr(AstVisitor *V, TypeName *e) { Resolver *R = V->state.R; Symbol *symbol = resolve_symbol(R, e->name); AstDecl *decl = symbol->decl; if (a_kind(decl) == DECL_VAR) { type_error(R, "'%s' is not a type", symbol->name->text); - } else if (a_is_struct_template_decl(decl)) { - StructDecl *base = &decl->struct_; - AstList *types = collect_expr_types(V, e->args); - e->type = init_struct_template(V, base, types); + } + e->type = instantiate(V, decl, e->args); +} + +static void visit_typelist_expr(AstVisitor *V, TypeList *e) +{ + AstType *r = new_type(V->state.R, NO_DECL, AST_TYPE_TUPLE); + r->tuple.elems = collect_expr_types(V, e->types); + e->type = r; +} + +static void visit_match_expr(AstVisitor *V, MatchExpr *e) +{ + Resolver *R = V->state.R; + AstType *target = resolve_expr(V, e->target); + + struct MatchState ms = { + .outer = R->ms, + .target = target, + .match = e, + }; + R->ms = &ms; // for unifying match arm types + V->visit_expr_list(V, e->arms, V->visit_expr); + R->ms = ms.outer; + + e->type = ms.value == NULL + ? get_type(R, PAW_TUNIT) + : ms.value; +} + +static void visit_arm_expr(AstVisitor *V, MatchArm *e) +{ + Resolver *R = V->state.R; + struct MatchState *ms = R->ms; + enter_block(R, NULL); + + AstType *guard = resolve_pat(V, e->guard); + if (e->cond != NULL) { + expect_bool_expr(V, e->cond); + } + AstType *value = resolve_expr(V, e->value); + + unify(R, ms->target, guard); + if (ms->value != NULL) { + unify(R, ms->value, value); } else { - e->type = a_type(decl); + ms->value = value; } + e->scope = leave_block(R); + e->type = value; } static void visit_ident_expr(AstVisitor *V, AstIdent *e) { Symbol *symbol = resolve_symbol(V->state.R, e->name); - e->type = get_type(V->state.R, symbol->decl->hdr.def); + e->type = symbol->decl->hdr.type; } static void visit_logical_expr(AstVisitor *V, LogicalExpr *e) @@ -747,30 +872,23 @@ static void visit_logical_expr(AstVisitor *V, LogicalExpr *e) static void visit_chain_expr(AstVisitor *V, ChainExpr *e) { - AstType *type = resolve_expr(V, e->target); - // if (!a_is_object(e->target->hdr.type)) { - // type_error(R, "'?' operator requires an object"); - // } -} - -static void visit_cond_expr(AstVisitor *V, CondExpr *e) -{ - expect_bool_expr(V, e->cond); - AstType *lhs = resolve_expr(V, e->lhs); - AstType *rhs = resolve_expr(V, e->rhs); - unify(V->state.R, lhs, rhs); - e->type = lhs; + Resolver *R = V->state.R; + e->type = resolve_expr(V, e->target); + if (R->result == NULL) { + syntax_error(R, "'?' outside function body"); + } + unify(R, R->result, e->type); } static AstType *get_value_type(AstType *target) { - if (!a_is_adt(target)) { - return NULL; - } else if (target->adt.base == PAW_TVECTOR) { - return target->adt.types->data[0]; - } else if (target->adt.base == PAW_TMAP) { - return target->adt.types->data[1]; - } + if (a_is_adt(target)) { + if (target->adt.base == PAW_TVECTOR) { + return target->adt.types->data[0]; + } else if (target->adt.base == PAW_TMAP) { + return target->adt.types->data[1]; + } + } return NULL; } @@ -857,11 +975,9 @@ static void visit_binop_expr(AstVisitor *V, BinOpExpr *e) static void visit_signature_expr(AstVisitor *V, FuncType *e) { Resolver *R = V->state.R; - e->type = new_type(R, NO_DECL, AST_TYPE_FUNC); - e->type->func.base = NO_DECL; - e->type->func.types = pawA_list_new(V->ast); - e->type->func.params = collect_expr_types(V, e->params); - e->type->func.return_ = resolve_expr(V, e->return_); + e->type = new_type(R, NO_DECL, AST_TYPE_FPTR); + e->type->fptr.params = collect_expr_types(V, e->params); + e->type->fptr.result = resolve_expr(V, e->result); } static void visit_struct_decl(AstVisitor *V, StructDecl *d) @@ -890,20 +1006,18 @@ static void visit_var_decl(AstVisitor *V, VarDecl *d) static void visit_type_decl(AstVisitor *V, TypeDecl *d) { // TODO: generic parameters for aliases - Symbol *symbol = declare_symbol(V->state.R, d->name, cast_decl(d), - PAW_FALSE); + Symbol *symbol = declare_symbol(V->state.R, d->name, cast_decl(d), PAW_FALSE); d->type = resolve_expr(V, d->rhs); // unify(R, d->name, d->type); define_symbol(symbol); } -static AstList *add_unknowns(AstVisitor *V, AstList *generics) +static AstList *new_unknowns(AstVisitor *V, int count) { Resolver *R = V->state.R; AstList *binder = pawA_list_new(R->ast); - for (int i = 0; i < generics->count; ++i) { - AstDecl *decl = generics->data[i]; - AstType *unknown = pawU_new_unknown(R->U, decl->hdr.def); + for (int i = 0; i < count; ++i) { + AstType *unknown = pawU_new_unknown(R->U); pawA_list_push(V->ast, &binder, unknown); } return binder; @@ -916,7 +1030,7 @@ static AstList *infer_template_param(AstVisitor *V, AstList *generics, Resolver *R = V->state.R; enter_inference_ctx(R, &gs, NULL); - AstList *unknowns = add_unknowns(V, generics); + AstList *unknowns = new_unknowns(V, generics->count); AstList *replaced = prep_inference(V, generics, unknowns, params); // Attempt to determine a type for each generic parameter, using the @@ -951,11 +1065,9 @@ static AstType *init_func_template(AstVisitor *V, FuncDecl *base, return a_type(inst); } -static AstType *infer_func_template(AstVisitor *V, FuncDecl *base, - AstList *args) +static AstType *infer_func_template(AstVisitor *V, FuncDecl *base, AstList *args) { - AstList *types = - infer_template_param(V, base->generics, base->params, args); + AstList *types = infer_template_param(V, base->generics, base->params, args); AstDecl *inst = instantiate_func(V, base, types); return a_type(inst); } @@ -963,25 +1075,24 @@ static AstType *infer_func_template(AstVisitor *V, FuncDecl *base, static AstType *setup_call(AstVisitor *V, CallExpr *e) { Resolver *R = V->state.R; - AstType *target = resolve_expr(V, e->target); - if (!a_is_func(target)) { + V->visit_expr(V, e->target); + AstType *t = a_type(e->target); + if (!a_is_func(t)) { type_error(R, "type is not callable"); - } - AstFuncSig *func = &target->func; - if (e->args->count < func->params->count) { + } else if (e->args->count < t->fptr.params->count) { syntax_error(R, "not enough arguments"); - } else if (e->args->count > func->params->count) { + } else if (e->args->count > t->fptr.params->count) { syntax_error(R, "too many arguments"); } - if (func->def != NO_DECL) { + if (a_is_fdef(t)) { // Function type has an associated declaration. If that declaration is // for a function template, attempt to infer the type parameters. - AstDecl *decl = get_decl(V->state.R, func->def); + AstDecl *decl = get_decl(V->state.R, t->func.did); if (a_is_func_template_decl(decl)) { return infer_func_template(V, &decl->func, e->args); } } - return target; + return t; } static void visit_call_expr(AstVisitor *V, CallExpr *e) @@ -990,17 +1101,14 @@ static void visit_call_expr(AstVisitor *V, CallExpr *e) // Determine the type of the callable, then find its declaration. Template // functions will need type inference, which is handled in setup_call(). e->func = setup_call(V, e); - e->type = e->func->func.return_; - if (a_kind(e->func) != AST_TYPE_FUNC) { - type_error(R, "type is not callable"); - } - AstFuncSig *func = &e->func->func; - AstList *params = func->params; + + const AstList *params = params = e->func->fptr.params; + e->type = e->func->fptr.result; + if (params->count != e->args->count) { - syntax_error(R, "expected %d parameter(s) but found %d", - func->params->count, e->args->count); + syntax_error(R, "expected %d arguments(s) but found %d", + params->count, e->args->count); } - // check call arguments against function parameters for (int i = 0; i < params->count; ++i) { AstExpr *arg = e->args->data[i]; AstType *type = resolve_expr(V, arg); @@ -1009,29 +1117,58 @@ static void visit_call_expr(AstVisitor *V, CallExpr *e) } } +static void visit_conversion_expr(AstVisitor *V, ConversionExpr *e) +{ + Resolver *R = V->state.R; + AstType *arg = resolve_expr(V, e->arg); + if (!a_is_adt(arg) || arg->adt.did == PAW_TUNIT || arg->adt.did == PAW_TSTRING) { + type_error(R, "argument to conversion must be scalar"); + } + e->type = get_type(R, e->to); +} + +static AstType *visit_tuple_lit(AstVisitor *V, LiteralExpr *lit) +{ + AstType *r = new_type(V->state.R, NO_DECL, AST_TYPE_TUPLE); + r->tuple.elems = collect_expr_types(V, lit->tuple.elems); + return r; +} + struct StructPack { String *name; AstList *fields; + AstType *type; + paw_Bool is_struct; }; static struct StructPack unpack_struct(Resolver *R, AstType *type) { - paw_assert(a_kind(type) == AST_TYPE_ADT); - AstDecl *decl = get_decl(R, type->adt.def); - if (a_kind(decl) == DECL_INSTANCE) { - AstDecl *base = get_decl(R, type->adt.base); + if (!a_is_func(type) && !a_is_adt(type)) { + type_error(R, "expected structure or enumerator"); + } + if (a_is_func(type)) { + AstDecl *decl = get_decl(R, type->func.did); return (struct StructPack){ - .name = base->struct_.name, - .fields = decl->inst.fields, + .name = decl->variant.name, + .fields = decl->variant.fields, + .type = decl->variant.type, }; } - - if (a_kind(decl) != DECL_STRUCT) { - type_error(R, "expected structure"); + AstDecl *decl = get_decl(R, type->adt.did); + if (a_is_struct_decl(decl)) { + return (struct StructPack){ + .is_struct = decl->struct_.is_struct, + .name = decl->struct_.name, + .fields = decl->struct_.fields, + .type = decl->struct_.type, + }; } + AstDecl *base = get_decl(R, type->adt.base); return (struct StructPack){ - .name = decl->struct_.name, - .fields = decl->struct_.fields, + .is_struct = base->struct_.is_struct, + .name = base->struct_.name, + .fields = decl->inst.fields, + .type = decl->inst.type, }; } @@ -1090,9 +1227,6 @@ static String *resolve_struct_key(AstVisitor *V, const struct StructPack *pack, return item->key->name.name; } -// TODO: scratch allocations need to be boxed -// could allow unnamed fields for other classes if they are in the correct -// order already static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) { CompositeLit *e = &lit->comp; @@ -1100,7 +1234,8 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) Lex *lex = R->lex; // Replace the AstIdent or IndexExpr with the TypeName of the structure. - AstType *target = resolve_expr(V, e->target); + V->visit_expr(V, e->target); + AstType *target = a_type(e->target); if (!a_is_adt(target)) { type_error(R, "expected structure type"); } else if (target->adt.base == PAW_TVECTOR) { @@ -1108,8 +1243,7 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) } else if (target->adt.base == PAW_TMAP) { return visit_map_lit(V, e, target); } - // Use a temporary Map to avoid searching repeatedly through the - // list of attributes. + // Use a temporary Map to avoid searching repeatedly through the list of fields. paw_Env *P = env(lex); Value *pv = pawC_push0(P); Map *map = pawH_new(P); @@ -1117,7 +1251,7 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) Value key; const struct StructPack pack = unpack_struct(R, target); - AstExpr **order = pawM_new_vec(P, e->items->count, AstExpr *); + AstList *order = pawA_list_new(R->ast); for (int i = 0; i < e->items->count; ++i) { AstExpr *item = e->items->data[i]; String *k = resolve_struct_key(V, &pack, &item->item, i); @@ -1128,7 +1262,7 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) } Value *value = pawH_action(P, map, key, MAP_ACTION_CREATE); v_set_int(value, i); - order[i] = item; + pawA_list_push(R->ast, &order, item); } for (int i = 0; i < pack.fields->count; ++i) { AstDecl *decl = pack.fields->data[i]; @@ -1140,9 +1274,9 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) field->name->text, pack.name->text); } else { const paw_Int index = v_int(*value); - ItemExpr *ie = &order[index]->item; - ie->index = i; // index of attribute in struct - unify(R, ie->type, get_type(R, field->def)); + AstExpr *item = order->data[index]; + item->item.index = i; // index of attribute in struct + unify(R, a_type(item), get_type(R, field->def)); } pawH_remove(P, map, key); } @@ -1151,9 +1285,8 @@ static AstType *visit_composite_lit(AstVisitor *V, LiteralExpr *lit) pack.name->text); } paw_assert(pack.fields->count == e->items->count); - + pawA_list_free(R->ast, order); pawC_pop(P); // pop map - pawM_free_vec(P, order, e->items->count); return target; } @@ -1161,6 +1294,8 @@ static void visit_literal_expr(AstVisitor *V, LiteralExpr *e) { if (e->lit_kind == LIT_BASIC) { e->type = get_type(V->state.R, e->basic.t); + } else if (e->lit_kind == LIT_TUPLE) { + e->type = visit_tuple_lit(V, e); } else { paw_assert(e->lit_kind == LIT_COMPOSITE); e->type = visit_composite_lit(V, e); @@ -1169,8 +1304,7 @@ static void visit_literal_expr(AstVisitor *V, LiteralExpr *e) static void visit_func_decl(AstVisitor *V, FuncDecl *d) { - Symbol *symbol = - declare_symbol(V->state.R, d->name, cast_decl(d), d->is_global); + Symbol *symbol = declare_symbol(V->state.R, d->name, cast_decl(d), d->is_global); symbol->is_type = d->generics->count > 0; register_base_func(V, d); visit_func(V, d, FUNC_FUNCTION); @@ -1186,7 +1320,6 @@ static void visit_if_stmt(AstVisitor *V, IfStmt *s) static void visit_expr_stmt(AstVisitor *V, AstExprStmt *s) { -pawA_dump_expr(stderr, cast_expr(s->lhs)); AstType *lhs = resolve_expr(V, s->lhs); if (s->rhs != NULL) { AstType *rhs = resolve_expr(V, s->rhs); @@ -1281,45 +1414,122 @@ static void visit_index_expr(AstVisitor *V, Index *e) Resolver *R = V->state.R; AstType *target = resolve_expr(V, e->target); - AstDecl *decl = get_decl(R, target->hdr.def); - if (!a_is_template_decl(decl)) { - if (e->elems->count != 1) { - syntax_error(R, "too many indices (must be 1)"); - } - AstType *expect = NULL; - if (target->adt.base == PAW_TVECTOR) { - expect = get_type(R, PAW_TINT); - e->type = target->adt.types->data[0]; - } else if (target->adt.base == PAW_TMAP) { - expect = target->adt.types->data[0]; - e->type = target->adt.types->data[1]; - } else { - type_error(R, "value cannot be indexed (not a container)"); - } - AstExpr *elem = e->elems->data[0]; - AstType *key_t = resolve_expr(V, elem); - unify(R, expect, key_t); - } else if (a_kind(decl) == DECL_STRUCT) { - e->type = explicit_struct_template(V, &decl->struct_, e); - } else { + if (a_is_fdef(target)) { + AstDecl *decl = get_decl(R, target->func.did); e->type = explicit_func_template(V, &decl->func, e); + return; + } + + if (!a_is_adt(target)) { + type_error(R, "value cannot be indexed"); + } + + AstDecl *decl = get_decl(R, target->adt.did); + if (target->adt.did == target->adt.base) { + if (decl->struct_.generics->count > 0) { + e->type = explicit_struct_template(V, &decl->struct_, e); + return; + } } + + if (e->elems->count != 1) { + syntax_error(R, "too many indices (must be 1)"); + } + AstType *expect = NULL; + if (target->adt.base == PAW_TVECTOR) { + expect = get_type(R, PAW_TINT); + e->type = target->adt.types->data[0]; + } else if (target->adt.base == PAW_TMAP) { + expect = target->adt.types->data[0]; + e->type = target->adt.types->data[1]; + } else { + type_error(R, "value cannot be indexed (not a container)"); + } + AstExpr *elem = e->elems->data[0]; + AstType *key_t = resolve_expr(V, elem); + unify(R, expect, key_t); } -static void visit_selector_expr(AstVisitor *V, Selector *e) +static AstDecl *expect_attr(Resolver *R, const struct StructPack *pack, String *name) +{ + AstDecl *attr = resolve_attr(pack->fields, name); + if (attr == NULL) { + syntax_error(R, "field '%s' does not exist in type '%s'", + name->text, pack->name->text); + } + return attr; +} + +static void visit_access_expr(AstVisitor *V, Access *e) { Resolver *R = V->state.R; AstType *type = resolve_expr(V, e->target); if (!a_is_adt(type)) { - type_error(R, "expected struct instance"); + type_error(R, "expected ADT"); } const struct StructPack pack = unpack_struct(R, type); - AstDecl *attr = resolve_attr(pack.fields, e->name); - if (attr == NULL) { - syntax_error(R, "attribute '%s' does not exist in struct '%s'", - e->name->text, pack.name->text); + if (pack.is_struct) { + type_error(R, "static fields are not supported on structures"); } - e->type = get_type(R, attr->hdr.def); + AstDecl *attr = expect_attr(R, &pack, e->name); + e->type = attr->hdr.type; +} + +static void visit_tuple_selector(AstVisitor *V, AstType *target, Selector *e) +{ + Resolver *R = V->state.R; + AstList *types = target->tuple.elems; + if (!e->is_index) { + type_error(R, "expected index of tuple element"); + } else if (e->index >= types->count) { + type_error(R, "expected element index"); + } + e->type = types->data[e->index]; +} + +static void visit_selector_expr(AstVisitor *V, Selector *e) +{ + Resolver *R = V->state.R; + AstType *type = resolve_expr(V, e->target); + if (a_is_tuple(type)) { + visit_tuple_selector(V, type, e); + return; + } else if (e->is_index) { + type_error(R, "expected name of struct field"); + } else if (!a_is_adt(type)) { + type_error(R, "expected ADT"); + } + // TODO: Prevent enum variants from appearing as 'target' here: only can access + // variant fields by unpacking after matching, so that we always unpack the + // correct variant + const struct StructPack pack = unpack_struct(R, type); + AstDecl *attr = expect_attr(R, &pack, e->name); + e->type = attr->hdr.type; +} + +static AstType *resolve_base(AstVisitor *V, AstPathSegment *base) +{ + Symbol *symbol = resolve_symbol(V->state.R, base->name); + return instantiate(V, symbol->decl, base->types); +} + +static AstType *next_segment(AstVisitor *V, AstType *base, AstPathSegment *next) +{ + Resolver *R = V->state.R; + const struct StructPack pack = unpack_struct(R, base); + AstDecl *attr = expect_attr(R, &pack, next->name); + return instantiate(V, attr, next->types); +} + +static AstType *resolve_path(AstVisitor *V, AstList *path) +{ + AstPathSegment *segment = pawA_path_get(path, 0); + AstType *type = resolve_base(V, segment); + for (int i = 1; i < path->count; ++i) { + segment = pawA_path_get(path, i); + type = next_segment(V, type, segment); + } + return type; } static void visit_decl_stmt(AstVisitor *V, AstDeclStmt *s) @@ -1327,6 +1537,113 @@ static void visit_decl_stmt(AstVisitor *V, AstDeclStmt *s) V->visit_decl(V, s->decl); } +static void visit_literal_pat(AstVisitor *V, AstLiteralPat *p) +{ + V->visit_expr(V, p->expr); +} + +static void visit_path_pat(AstVisitor *V, AstPathPat *p) +{ + p->type = resolve_path(V, p->path); +} + +static void visit_tuple_pat(AstVisitor *V, AstTuplePat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void try_bind_var(Resolver *R, AstPat *pat, AstType *want) +{ + if (a_kind(pat) == AST_PAT_PATH && pat->path.path->count == 1) { + AstPathSegment *segment = pat->path.path->data[0]; + if (segment->types->count == 0) { + Symbol *symbol = try_resolve_symbol(R, segment->name); + if (symbol == NULL || !symbol->is_type || a_is_func_decl(symbol->decl)) { + // TODO: don't abuse 'is_type' flag for function templates, shouldn't need to check if the symbol + // is a function or not here + AstDecl *r = pawA_new_decl(R->ast, DECL_VAR); + r->var.name = segment->name; + new_symbol(R, segment->name, r, PAW_FALSE); + add_decl(R, r); + } else { + AstType *have = a_type(symbol->decl); + unify(R, have, want); + } + } + } +} + +static AstType *resolve_sfield_pat(AstVisitor *V, const struct StructPack *pack, AstFieldPat *p) +{ + Resolver *R = V->state.R; + paw_assert(pack->is_struct); + paw_assert(p->name != NULL); + AstDecl *attr = resolve_attr(pack->fields, p->name); + if (attr == NULL) { + syntax_error(R, "field '%s' does not exist in type '%s'", + p->name->text, pack->name->text); + } + p->type = a_type(attr); + try_bind_var(R, p->pat, p->type); + return p->type; +} + +static AstType *resolve_vfield_pat(AstVisitor *V, const struct StructPack *pack, AstFieldPat *p, int index) +{ + Resolver *R = V->state.R; + paw_assert(!pack->is_struct); + paw_assert(p->name == NULL); + AstDecl *decl = pack->fields->data[index]; + p->type = a_type(decl); + try_bind_var(R, p->pat, p->type); + return p->type; +} + +static void visit_struct_pat(AstVisitor *V, AstStructPat *p) +{ + Resolver *R = V->state.R; + p->type = resolve_path(V, p->path); + + const struct StructPack pack = unpack_struct(R, p->type); + if (!pack.is_struct) { + type_error(R, "expected struct '%s'", pack.name->text); + } else if (pack.fields->count != p->fields->count) { + syntax_error(R, "missing fields from struct pattern for '%s'", pack.name->text); + } + for (int i = 0; i < p->fields->count; ++i) { + AstPat *pat = p->fields->data[i]; + AstFieldPat *field = &pat->field; + field->type = resolve_sfield_pat(V, &pack, field); + + AstDecl *attr = resolve_attr(pack.fields, field->name); + unify(R, a_type(attr), field->type); + } +} + +static void visit_variant_pat(AstVisitor *V, AstVariantPat *p) +{ + Resolver *R = V->state.R; + AstType *target = resolve_path(V, p->path); + paw_assert(a_is_func(target)); + p->type = target->func.result; + + const struct StructPack pack = unpack_struct(R, target); + if (pack.is_struct) { + type_error(R, "expected variant '%s'", pack.name->text); + } else if (pack.fields->count != p->elems->count) { + syntax_error(R, "missing fields from variant pattern for '%s'", pack.name->text); + } + for (int i = 0; i < p->elems->count; ++i) { + AstPat *pat = p->elems->data[i]; + AstFieldPat *field = &pat->field; + field->type = resolve_vfield_pat(V, &pack, field, i); + + const AstDecl *expect = pack.fields->data[i]; + unify(R, a_type(expect), field->type); + } +} + static void visit_prelude_func(AstVisitor *V, FuncDecl *d) { Symbol *symbol = @@ -1342,43 +1659,9 @@ static void visit_prelude_struct(AstVisitor *V, StructDecl *d) register_base_struct(V, d); } -static void setup_globals(Resolver *R) -{ - paw_Env *P = env(R->lex); - return; - for (int i = 0; i < P->gv.size; ++i) { - // TODO: global type info -> AST type node for globals - GlobalVar g = P->gv.data[i]; - AstDecl *d = pawA_new_decl(R->ast, DECL_FUNC); - d->func.type = R->ast->builtin[g.desc.code]; - d->func.is_global = PAW_TRUE; - const DefId id = add_decl(R, d); - - AstType *type = new_type(R, id, AST_TYPE_FUNC); - if (0 == strcmp(g.desc.name->text, - "assert")) { // TODO: Write a function that parses type - // info into an AST type - type->func.params = pawA_list_new(R->ast); - pawA_list_push(R->ast, &type->func.params, get_type(R, PAW_TBOOL)); - type->func.return_ = get_type(R, PAW_TUNIT); - } else if (0 == strcmp(g.desc.name->text, "print")) { - type->func.params = pawA_list_new(R->ast); - pawA_list_push(R->ast, &type->func.params, - get_type(R, PAW_TSTRING)); - type->func.return_ = get_type(R, PAW_TUNIT); - } else { - paw_assert(0); - } - d->func.type = type; - type->func.def = type->func.base = id; - Symbol *s = add_global(R, g.desc.name, d); - define_symbol(s); - } -} - static void add_basic_builtin(Resolver *R, String *name) { - AstExpr *e = pawA_new_expr(R->ast, EXPR_TYPE_NAME); + AstExpr *e = pawA_new_expr(R->ast, EXPR_TYPENAME); e->type_name.args = pawA_list_new(R->ast); e->type_name.name = name; @@ -1397,31 +1680,39 @@ static void add_basic_builtin(Resolver *R, String *name) static void visit_prelude(AstVisitor *V, Resolver *R) { - add_basic_builtin(R, cached_str(R, CSTR_UNIT)); - add_basic_builtin(R, cached_str(R, CSTR_BOOL)); - add_basic_builtin(R, cached_str(R, CSTR_INT)); - add_basic_builtin(R, cached_str(R, CSTR_FLOAT)); - add_basic_builtin(R, cached_str(R, CSTR_STRING)); - - // no generic context - R->U->depth = -1; - - setup_globals(R); - const AstState state = {.R = R}; pawA_visitor_init(V, R->ast, state); V->visit_func_decl = visit_prelude_func; V->visit_struct_decl = visit_prelude_struct; - V->visit_type_name_expr = visit_type_name_expr; + V->visit_typename_expr = visit_typename_expr; V->visit_signature_expr = visit_signature_expr; V->visit_stmt_list(V, R->ast->prelude, V->visit_stmt); } -static void setup_module(AstVisitor *V, Resolver *R) +static void setup_module(AstVisitor *V, Resolver *R, AstDecl *r) { + add_basic_builtin(R, cached_str(R, CSTR_UNIT)); + add_basic_builtin(R, cached_str(R, CSTR_BOOL)); + add_basic_builtin(R, cached_str(R, CSTR_INT)); + add_basic_builtin(R, cached_str(R, CSTR_FLOAT)); + add_basic_builtin(R, cached_str(R, CSTR_STRING)); + + R->U->depth = -1; + + r->func.type = new_type(R, NO_DECL, AST_TYPE_FUNC); + r->func.type->func.types = pawA_list_new(R->ast); + r->func.type->func.params = pawA_list_new(R->ast); + r->func.type->func.result = get_type(R, PAW_TUNIT); + r->func.params = pawA_list_new(R->ast); + visit_prelude(V, R); + Symbol *symbol = resolve_symbol(R, scan_string(R->lex, "Option")); + R->option_did = symbol->decl->struct_.def; + symbol = resolve_symbol(R, scan_string(R->lex, "Result")); + R->result_did = symbol->decl->struct_.def; + const AstState state = {.R = R}; pawA_visitor_init(V, R->ast, state); V->visit_literal_expr = visit_literal_expr; @@ -1430,12 +1721,16 @@ static void setup_module(AstVisitor *V, Resolver *R) V->visit_chain_expr = visit_chain_expr; V->visit_unop_expr = visit_unop_expr; V->visit_binop_expr = visit_binop_expr; - V->visit_cond_expr = visit_cond_expr; + V->visit_conversion_expr = visit_conversion_expr; V->visit_call_expr = visit_call_expr; V->visit_index_expr = visit_index_expr; + V->visit_access_expr = visit_access_expr; V->visit_selector_expr = visit_selector_expr; // V->visit_item_expr = visit_item_expr; - V->visit_type_name_expr = visit_type_name_expr; + V->visit_typename_expr = visit_typename_expr; + V->visit_typelist_expr = visit_typelist_expr; + V->visit_match_expr = visit_match_expr; + V->visit_arm_expr = visit_arm_expr; V->visit_signature_expr = visit_signature_expr; V->visit_block_stmt = visit_block_stmt; V->visit_expr_stmt = visit_expr_stmt; @@ -1446,9 +1741,15 @@ static void setup_module(AstVisitor *V, Resolver *R) V->visit_dowhile_stmt = visit_dowhile_stmt; V->visit_return_stmt = visit_return_stmt; V->visit_var_decl = visit_var_decl; + V->visit_variant_decl = visit_variant_decl; V->visit_func_decl = visit_func_decl; V->visit_struct_decl = visit_struct_decl; V->visit_type_decl = visit_type_decl; + V->visit_literal_pat = visit_literal_pat; + V->visit_path_pat = visit_path_pat; + V->visit_tuple_pat = visit_tuple_pat; + V->visit_struct_pat = visit_struct_pat; + V->visit_variant_pat = visit_variant_pat; } static void visit_module(Resolver *R) @@ -1456,10 +1757,12 @@ static void visit_module(Resolver *R) Lex *lex = R->lex; SymbolTable *sym = R->sym; AstDecl *r = pawA_new_decl(R->ast, DECL_FUNC); - enter_function(R, lex->modname, NULL, &r->func); + r->func.name = lex->modname; + + enter_function(R, NULL, &r->func); AstVisitor V; - setup_module(&V, R); + setup_module(&V, R, r); pawA_visit(&V); sym->toplevel = leave_function(R); diff --git a/src/code.h b/src/code.h index 18189e2..634d570 100644 --- a/src/code.h +++ b/src/code.h @@ -37,7 +37,6 @@ void *pawK_pool_alloc(paw_Env *P, Pool *pool, size_t size, size_t align); typedef struct Generator { Lex *lex; // lexical state - StructState *cs; // enclosing structure context FuncState *fs; // enclosing function context SymbolTable *sym; // scoped symbol table Scope *globals; // global symbols diff --git a/src/codegen.c b/src/codegen.c index 47cd2c1..952d0ea 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -43,28 +43,33 @@ static void mangle_type(Generator *G, Buffer *buf, AstType *type) } else if (a_is_generic(type)) { AstGeneric *var = &type->generic; pawL_add_nstring(P, buf, var->name->text, var->name->length); + } else if (a_is_tuple(type)) { + AstTupleType *tup = &type->tuple; + pawL_add_char(P, buf, 'T'); + for (int i = 0; i < tup->elems->count; ++i) { + mangle_type(G, buf, tup->elems->data[i]); + } + pawL_add_char(P, buf, '_'); } else if (a_is_adt(type)) { AstAdt *adt = &type->adt; - AstDecl *d = get_decl(G, adt->def); + AstDecl *d = get_decl(G, adt->did); String *name = d->struct_.name; pawL_add_nstring(P, buf, name->text, name->length); for (int i = 0; i < adt->types->count; ++i) { mangle_type(G, buf, adt->types->data[i]); } } else { - paw_assert(a_is_func(type)); - AstFuncSig *func = &type->func; + paw_assert(a_is_func(type) || a_is_fptr(type)); pawL_add_char(P, buf, 'F'); - AstList *params = func->params; - for (int i = 0; i < params->count; ++i) { - mangle_type(G, buf, params->data[i]); + for (int i = 0; i < type->fptr.params->count; ++i) { + mangle_type(G, buf, type->fptr.params->data[i]); } pawL_add_char(P, buf, '_'); - mangle_type(G, buf, func->return_); + mangle_type(G, buf, type->fptr.result); } } -// mangle('name', ()) -> name_ +// mangle('name', ()) -> name0_ // mangle('name', ('int', 'A')) -> nameiA_ // mangle('name', ('A[int]',)) -> nameAi_ static String *mangle_name(Generator *G, String *name, AstList *binder) @@ -93,12 +98,8 @@ static String *get_type_name(Generator *G, AstType *type) static paw_Type basic_code(const AstType *type) { - if (a_kind(type) == AST_TYPE_ADT) { - return type->adt.base; - } else { - paw_assert(a_kind(type) == AST_TYPE_BASIC); - return type->hdr.def; - } + paw_assert(a_is_adt(type)); + return type->adt.base; } // TODO: Get rid of this @@ -113,7 +114,7 @@ static void push_local_table(FuncState *fs, Scope *symbols) { Generator *G = fs->G; SymbolTable *st = &fs->scopes; - if (st->nscopes == UINT16_MAX) { + if (st->nscopes == ITEM_MAX) { syntax_error(G, "too many nested scopes"); } pawM_grow(env(G->lex), st->scopes, st->nscopes, st->capacity); @@ -134,16 +135,10 @@ static int add_constant(Generator *G, Value v) FuncState *fs = G->fs; Proto *p = fs->proto; - if (fs->nk == UINT16_MAX) { + if (fs->nk == ITEM_MAX) { syntax_error(G, "too many constants"); - } else if (fs->nk == p->nk) { - // 'fs->nk' only ever increases by 1, so this will always give us - // enough memory. - pawM_grow(env(G->lex), p->k, fs->nk, p->nk); - for (int i = fs->nk + 1; i < p->nk; ++i) { - v_set_0(&p->k[i]); // clear for GC - } } + pawM_grow(env(G->lex), p->k, fs->nk, p->nk); p->k[fs->nk] = v; return fs->nk++; } @@ -152,7 +147,7 @@ static int add_struct(Generator *G, Struct *struct_) { paw_Env *P = env(G->lex); struct StructVec *sv = &P->sv; - if (sv->size == UINT16_MAX) { + if (sv->size == ITEM_MAX) { syntax_error(G, "too many structs"); } pawM_grow(P, sv->data, sv->size, sv->alloc); @@ -160,64 +155,39 @@ static int add_struct(Generator *G, Struct *struct_) return sv->size++; } -static int add_proto(Generator *G, String *name, Proto **pp) +static int add_proto(Generator *G, FuncDecl *d, Proto **pp) { Lex *lex = G->lex; FuncState *fs = G->fs; Proto *p = fs->proto; - if (fs->nproto == UINT16_MAX) { + if (fs->nproto == ITEM_MAX) { syntax_error(G, "too many functions"); - } else if (fs->nproto == p->nproto) { - pawM_grow(env(lex), p->p, fs->nproto, p->nproto); - for (int i = fs->nproto; i < p->nproto; ++i) { - p->p[i] = NULL; // clear for GC (including current) - } } + pawM_grow(env(lex), p->p, fs->nproto, p->nproto); Proto *callee = pawV_new_proto(env(lex)); callee->modname = lex->modname; - callee->name = name; + callee->name = d->name; const int id = fs->nproto++; p->p[id] = *pp = callee; return id; } -static void add_debug_info(Generator *G, Symbol *symbol) +static paw_Bool needs_close(FuncState *fs, const BlockState *bs) { - FuncState *fs = G->fs; - Proto *p = fs->proto; - if (fs->ndebug == LOCAL_MAX) { - syntax_error(G, "too many locals"); - } else if (fs->ndebug == p->ndebug) { - pawM_grow(env(G->lex), p->v, fs->ndebug, p->ndebug); - for (int i = fs->ndebug + 1; i < p->ndebug; ++i) { - p->v[i].var = (VarDesc){0}; // clear for GC + for (int i = fs->level - 1; i >= bs->level; --i) { + if (fs->locals.slots[i].is_captured) { + return PAW_TRUE; } } - p->v[fs->ndebug] = (struct LocalInfo){ - .var = {symbol->name, symbol->decl->hdr.def}, - .pc0 = fs->pc, - }; - ++fs->ndebug; -} - -static struct LocalInfo *local_info(FuncState *fs, int level) -{ - return &fs->proto->v[level]; + return PAW_FALSE; } -static void close_vars(FuncState *fs, int target) +static void close_vars(FuncState *fs, const BlockState *bs) { - const int upper = fs->level - 1; // first slot to pop - const int lower = target - 1; // 1 past 'reverse' end - paw_assert(lower <= upper); - for (int i = upper; i > lower; --i) { - struct LocalInfo *local = local_info(fs, i); - if (local->captured) { - pawK_code_0(fs, OP_CLOSE); - } else { - pawK_code_0(fs, OP_POP); - } + if (fs->level > bs->level) { + const Op op = needs_close(fs, bs) ? OP_CLOSE : OP_POP; + pawK_code_U(fs, op, fs->level - bs->level); } } @@ -228,7 +198,7 @@ static VarInfo add_local(FuncState *fs, Symbol *symbol) fs->locals.capacity); const int index = fs->locals.nslots++; fs->locals.slots[index].symbol = symbol; - fs->locals.slots[index].index = index; // TODO + fs->locals.slots[index].index = index; return (VarInfo){ .symbol = symbol, .kind = VAR_LOCAL, @@ -250,8 +220,7 @@ static VarInfo transfer_local(FuncState *fs) // Find the next symbol that belongs on the stack. SymbolTable *scopes = &fs->scopes; // all function scopes Scope *scope = scopes->scopes[scopes->nscopes - 1]; // last scope - while (symbol_iter(fs, scope, &symbol)) { - } + while (symbol_iter(fs, scope, &symbol)) {} return add_local(fs, symbol); } @@ -260,7 +229,7 @@ static VarInfo transfer_global(Generator *G) const int index = G->iglobal++; Symbol *symbol = G->globals->symbols[index]; pawE_new_global(env(G->lex), symbol->name, - a_type_code(a_type(symbol->decl))); // TODO + a_type(symbol->decl)->adt.did); // TODO return (VarInfo){ .symbol = symbol, .kind = VAR_GLOBAL, @@ -315,7 +284,7 @@ static void add_label(FuncState *fs, LabelKind kind) ll->values[ll->length] = (Label){ .kind = kind, .line = lex->line, - .level = fs->proto->ndebug, + .level = fs->level - fs->bs->level, .pc = code_jump(fs, OP_JUMP), }; ++ll->length; @@ -376,19 +345,11 @@ static void adjust_to(FuncState *fs, LabelKind kind, int to) static void begin_local_scope(FuncState *fs, int n) { - LocalStack *locals = &fs->locals; - for (int i = 0; i < n; ++i) { - const int level = fs->level++; - LocalSlot slot = locals->slots[level]; - add_debug_info(fs->G, slot.symbol); - } + fs->level += n; } static void end_local_scope(FuncState *fs, BlockState *bs) { - for (int i = fs->level - 1; i >= bs->level; --i) { - local_info(fs, i)->pc1 = fs->pc; - } fs->locals.nslots = bs->level; fs->level = bs->level; } @@ -399,7 +360,7 @@ static void leave_block(FuncState *fs) if (bs->is_loop) { adjust_from(fs, LBREAK); } - close_vars(fs, bs->level); + close_vars(fs, bs); end_local_scope(fs, bs); if (bs->outer) { adjust_labels(fs, bs); @@ -444,8 +405,6 @@ static void leave_function(Generator *G) p->nlines = fs->nlines; pawM_shrink(env(lex), p->p, p->nproto, fs->nproto); p->nproto = fs->nproto; - pawM_shrink(env(lex), p->v, p->ndebug, fs->ndebug); - p->ndebug = fs->ndebug; pawM_shrink(env(lex), p->u, p->nup, fs->nup); p->nup = fs->nup; pawM_shrink(env(lex), p->k, p->nk, fs->nk); @@ -455,23 +414,13 @@ static void leave_function(Generator *G) check_gc(env(lex)); } -static String *context_name(const FuncState *fs, FuncKind kind) -{ - if (fn_has_self(kind)) { - return scan_string(fs->G->lex, "(self)"); - } - return fs->proto->name; -} - static void enter_function(Generator *G, FuncState *fs, BlockState *bs, Scope *scope, FuncKind kind) { - fs->id = -1; // TODO: not used fs->bs = NULL; fs->scopes = (SymbolTable){0}; fs->locals = (LocalStack){0}; fs->nstructs = 0; - fs->ndebug = 0; fs->nproto = 0; fs->nlines = 0; fs->level = 0; @@ -532,8 +481,7 @@ static VarInfo resolve_attr(Generator *G, AstType *type, String *name) return info; } -static void add_upvalue(FuncState *fs, String *name, VarInfo *info, - paw_Bool is_local) +static void add_upvalue(FuncState *fs, VarInfo *info, paw_Bool is_local) { Proto *f = fs->proto; for (int i = 0; i < fs->nup; ++i) { @@ -546,14 +494,9 @@ static void add_upvalue(FuncState *fs, String *name, VarInfo *info, } if (fs->nup == UPVALUE_MAX) { syntax_error(fs->G, "too many upvalues"); - } else if (fs->nup == f->nup) { - pawM_grow(env(fs->G->lex), f->u, fs->nup, f->nup); - for (int i = fs->nup + 1; i < f->nup; ++i) { - f->u[i].var = (VarDesc){0}; // clear for GC - } } + pawM_grow(env(fs->G->lex), f->u, fs->nup, f->nup); f->u[fs->nup] = (struct UpValueInfo){ - .var = {name, info->symbol->decl->hdr.def}, .is_local = is_local, .index = info->index, }; @@ -564,18 +507,16 @@ static void add_upvalue(FuncState *fs, String *name, VarInfo *info, static paw_Bool resolve_upvalue(FuncState *fs, String *name, VarInfo *pinfo) { FuncState *caller = fs->outer; - if (!caller) { // base case + if (!caller) { return PAW_FALSE; } - // Check the caller's local variables. if (resolve_local(caller, name, pinfo)) { - caller->proto->v[pinfo->index].captured = PAW_TRUE; - add_upvalue(fs, name, pinfo, PAW_TRUE); + caller->locals.slots[pinfo->index].is_captured = PAW_TRUE; + add_upvalue(fs, pinfo, PAW_TRUE); return PAW_TRUE; } - if (resolve_upvalue(caller, name, pinfo)) { - add_upvalue(fs, name, pinfo, PAW_FALSE); + add_upvalue(fs, pinfo, PAW_FALSE); return PAW_TRUE; } return PAW_FALSE; @@ -592,8 +533,7 @@ static void define_var(FuncState *fs, VarInfo info) if (info.kind == VAR_LOCAL) { begin_local_scope(fs, 1); } else { - // Write initial value to the globals table. Reference counts are - // adjusted automatically. + // Write initial value to the globals table. paw_assert(info.kind == VAR_GLOBAL); pawK_code_U(fs, OP_SETGLOBAL, info.index); } @@ -673,15 +613,19 @@ static void code_setter(AstVisitor *V, AstExpr *lhs, AstExpr *rhs) return; } - // index or field assignment - SuffixedExpr *suf = &lhs->suffix; // common base - V->visit_expr(V, suf->target); // push up to last expression + const SuffixedExpr *suf = &lhs->suffix; + V->visit_expr(V, suf->target); + if (a_kind(lhs) == EXPR_SELECTOR) { V->visit_expr(V, rhs); - // resolve the field index String *name = lhs->selector.name; - const VarInfo info = resolve_attr(G, a_type(suf->target), name); - pawK_code_U(fs, OP_SETATTR, info.index); + AstType *target = a_type(suf->target); + if (lhs->selector.is_index) { + pawK_code_U(fs, OP_SETTUPLE, lhs->selector.index); + } else { + const VarInfo info = resolve_attr(G, target, name); + pawK_code_U(fs, OP_SETATTR, info.index); + } } else { paw_assert(a_kind(lhs) == EXPR_INDEX); visit_exprs(V, lhs->index.elems); @@ -713,43 +657,52 @@ static void code_basic_lit(AstVisitor *V, LiteralExpr *e) } } -static void code_builtin_composite(AstVisitor *V, LiteralExpr *lit, unsigned op) +static void code_tuple_lit(AstVisitor *V, LiteralExpr *e) { - CompositeLit *e = &lit->comp; - visit_exprs(V, e->items); + TupleLit *lit = &e->tuple; + visit_exprs(V, lit->elems); FuncState *fs = V->state.G->fs; - pawK_code_U(fs, op, e->items->count); + pawK_code_U(fs, OP_NEWTUPLE, lit->elems->count); } -static void code_custom_composite(AstVisitor *V, LiteralExpr *lit) +static void code_builtin_composite(AstVisitor *V, LiteralExpr *e, unsigned op) { - CompositeLit *e = &lit->comp; + CompositeLit *lit = &e->comp; + visit_exprs(V, lit->items); + + FuncState *fs = V->state.G->fs; + pawK_code_U(fs, op, lit->items->count); +} + +static void code_custom_composite(AstVisitor *V, LiteralExpr *e) +{ + CompositeLit *lit = &e->comp; Generator *G = V->state.G; FuncState *fs = G->fs; - const DefId id = a_type_code(lit->type); - StructDecl *d = &get_decl(G, id)->struct_; + const DefId did = e->type->adt.did; + StructDecl *d = &get_decl(G, did)->struct_; pawK_code_U(G->fs, OP_PUSHSTRUCT, d->location); pawK_code_U(fs, OP_NEWINSTANCE, d->fields->count); - for (int i = 0; i < e->items->count; ++i) { - AstExpr *attr = e->items->data[i]; + for (int i = 0; i < lit->items->count; ++i) { + AstExpr *attr = lit->items->data[i]; V->visit_expr(V, attr); pawK_code_U(fs, OP_INITFIELD, attr->item.index); } } -static void code_composite_lit(AstVisitor *V, LiteralExpr *lit) +static void code_composite_lit(AstVisitor *V, LiteralExpr *e) { Generator *G = V->state.G; - String *name = get_type_name(G, a_type(lit->comp.target)); + String *name = get_type_name(G, a_type(e->comp.target)); if (pawS_eq(name, pawE_cstr(env(G->lex), CSTR_VECTOR))) { - code_builtin_composite(V, lit, OP_NEWVECTOR); + code_builtin_composite(V, e, OP_NEWVECTOR); } else if (pawS_eq(name, pawE_cstr(env(G->lex), CSTR_MAP))) { - code_builtin_composite(V, lit, OP_NEWVECTOR); + code_builtin_composite(V, e, OP_NEWVECTOR); } else { - code_custom_composite(V, lit); + code_custom_composite(V, e); } } @@ -759,6 +712,9 @@ static void code_literal_expr(AstVisitor *V, LiteralExpr *e) case LIT_BASIC: code_basic_lit(V, e); break; + case LIT_TUPLE: + code_tuple_lit(V, e); + break; default: code_composite_lit(V, e); } @@ -771,7 +727,7 @@ static void code_and(AstVisitor *V, LogicalExpr *e) V->visit_expr(V, e->lhs); const int jump = code_jump(fs, OP_JUMPFALSE); - pawK_code_0(fs, OP_POP); + pawK_code_U(fs, OP_POP, 1); V->visit_expr(V, e->rhs); patch_here(fs, jump); } @@ -785,7 +741,7 @@ static void code_or(AstVisitor *V, LogicalExpr *e) const int else_jump = code_jump(fs, OP_JUMPFALSE); const int then_jump = code_jump(fs, OP_JUMP); patch_here(fs, else_jump); - pawK_code_0(fs, OP_POP); + pawK_code_U(fs, OP_POP, 1); V->visit_expr(V, e->rhs); patch_here(fs, then_jump); } @@ -805,25 +761,9 @@ static void code_chain_expr(AstVisitor *V, ChainExpr *e) FuncState *fs = G->fs; V->visit_expr(V, e->target); - const int else_jump = code_jump(fs, OP_JUMPNULL); - const int then_jump = code_jump(fs, OP_JUMP); - patch_here(fs, else_jump); + const int jump = code_jump(fs, OP_JUMPNULL); pawK_code_0(fs, OP_RETURN); - patch_here(fs, then_jump); -} - -static void code_cond_expr(AstVisitor *V, CondExpr *e) -{ - FuncState *fs = V->state.G->fs; - - V->visit_expr(V, e->cond); - const int else_jump = code_jump(fs, OP_JUMPFALSEPOP); - V->visit_expr(V, e->lhs); - const int then_jump = code_jump(fs, OP_JUMP); - patch_here(fs, else_jump); - // same type as 'e->lhs' - V->visit_expr(V, e->rhs); - patch_here(fs, then_jump); + patch_here(fs, jump); } #define code_op(fs, op, subop, type) \ @@ -861,7 +801,7 @@ static void code_expr_stmt(AstVisitor *V, AstExprStmt *s) return; } V->visit_expr(V, s->lhs); // function call - pawK_code_0(fs, OP_POP); // unused return value + pawK_code_U(fs, OP_POP, 1); // unused return value } static void code_func(AstVisitor *V, FuncDecl *d) @@ -872,8 +812,8 @@ static void code_func(AstVisitor *V, FuncDecl *d) fs.name = d->name; fs.G = G; - AstFuncSig *func = &d->type->func; - const int id = add_proto(G, d->name, &fs.proto); + AstFuncDef *func = &d->type->func; + const int id = add_proto(G, d, &fs.proto); fs.proto->argc = func->params->count; enter_function(G, &fs, &bs, d->scope, d->fn_kind); visit_decls(V, d->params); // code parameters @@ -892,8 +832,7 @@ static void monomorphize_func(AstVisitor *V, FuncDecl *d) AstDecl *decl = d->monos->data[i]; FuncDecl *inst = pawA_stencil_func(V->ast, d, decl); String *mangled = mangle_name(G, inst->name, inst->type->func.types); - const VarInfo info = - inject_var(fs, mangled, cast_decl(inst), d->is_global); + const VarInfo info = inject_var(fs, mangled, cast_decl(inst), d->is_global); code_func(V, inst); define_var(fs, info); } @@ -921,8 +860,12 @@ static void code_struct_decl(AstVisitor *V, StructDecl *d) paw_Env *P = env(lex); Value *pv = pawC_push0(P); - Struct *struct_ = pawV_new_struct(P, pv); - d->location = add_struct(G, struct_); + if (d->is_struct) { + Struct *struct_ = pawV_new_struct(P, pv); + d->location = add_struct(G, struct_); + } else { + // TODO: Add enum RTTI stuff + } pawC_pop(P); // pop 'struct_' } @@ -931,6 +874,60 @@ static void code_item_expr(AstVisitor *V, ItemExpr *e) V->visit_expr(V, e->value); } +static void code_match_expr(AstVisitor *V, MatchExpr *e) +{ + V->visit_expr(V, e->target); + for (int i = 0; i < e->arms->count; ++i) { + V->visit_arm_expr(V, e->arms->data[i]); + } +} + +static int code_variant_guard(AstVisitor *V, AstVariantPat *p) +{ + Generator *G = V->state.G; + AstDecl *decl = get_decl(V, p->type->func.did); + const int k = decl->variant.index; + + // compare discriminator + pawK_code_0(G->fs, OP_COPY); + pawK_code_U(G->fs, OP_MATCHVARIANT, k); + const int next_case = code_jump(G->fs, OP_JUMPFALSEPOP); + + for (int i = 0; i < p->elems->count; ++i) { + AstPat *elem = p->elems->data[i]; + V->visit_pat(V, elem); + } + + return next_case; +} + +static int code_match_guard(AstVisitor *V, AstPat *guard) +{ + if (a_kind(guard) == AST_PAT_VARIANT) { + return code_variant_guard(V, &guard->variant); + } else if (a_kind(guard) == AST_PAT_STRUCT) { + + } else if (a_kind(guard) == AST_PAT_PATH) { + + } else { + + } + return -1; +} + +static void code_arm_expr(AstVisitor *V, MatchArm *e) +{ + BlockState bs; + Generator *G = V->state.G; + enter_block(G->fs, &bs, e->scope, PAW_FALSE); + + const int next_case = code_match_guard(V, e->guard); + V->visit_expr(V, e->value); + + patch_here(G->fs, next_case); + leave_block(G->fs); +} + static void code_block_stmt(AstVisitor *V, Block *b) { BlockState bs; @@ -952,21 +949,11 @@ static void code_return_stmt(AstVisitor *V, ReturnStmt *s) pawK_code_0(fs, OP_RETURN); } -static paw_Bool is_instance_call(const AstType *type) -{ - return type->func.types->count > 0; -} - -static AstDecl *get_base_decl(Generator *G, const AstType *type) -{ - return get_decl(G, a_is_adt(type) ? type->adt.base : type->func.def); -} - static void code_instance_getter(AstVisitor *V, AstType *type) { Generator *G = V->state.G; paw_assert(a_is_func(type)); - AstDecl *decl = get_decl(G, a_type_code(type)); + AstDecl *decl = get_decl(G, type->func.did); String *name = decl->hdr.name; paw_assert(a_is_func_decl(decl)); name = mangle_name(G, name, type->func.types); @@ -974,12 +961,55 @@ static void code_instance_getter(AstVisitor *V, AstType *type) code_getter(V, info); } +struct VariantInfo { + Scope *fields; + int choice; +}; + +static struct VariantInfo unpack_variant(Generator *G, AstType *type) +{ + AstDecl *decl = get_decl(G, type->func.did); + return (struct VariantInfo){ + .fields = decl->variant.scope, + .choice = decl->variant.index, + }; +} + +static paw_Bool is_instance_call(const AstType *type) +{ + return a_is_fdef(type) && type->func.types->count > 0; +} + +static paw_Bool is_variant_constructor(Generator *G, const AstType *type) +{ + if (a_is_fdef(type)) { + const AstDecl *decl = get_decl(G, type->func.did); + return a_kind(decl) == DECL_VARIANT; + } + return PAW_FALSE; +} + +// Generate code for an enumerator +static void code_variant_constructor(AstVisitor *V, AstType *type, AstList *args) +{ + Generator *G = V->state.G; + FuncState *fs = G->fs; + + struct VariantInfo info = unpack_variant(G, type); + visit_exprs(V, args); // field values + pawK_code_AB(fs, OP_NEWVARIANT, info.choice, args->count); +} + static void code_call_expr(AstVisitor *V, CallExpr *e) { + paw_assert(a_is_func(e->func)); Generator *G = V->state.G; FuncState *fs = G->fs; - if (is_instance_call(e->func)) { + if (is_variant_constructor(G, e->func)) { + code_variant_constructor(V, e->func, e->args); + return; + } else if (is_instance_call(e->func)) { code_instance_getter(V, e->func); } else { V->visit_expr(V, e->target); @@ -988,6 +1018,18 @@ static void code_call_expr(AstVisitor *V, CallExpr *e) pawK_code_U(fs, OP_CALL, e->args->count); } +static void code_conversion_expr(AstVisitor *V, ConversionExpr *e) +{ + Generator *G = V->state.G; + const AstType *from = a_type(e->arg); + const Op op = e->to == PAW_TBOOL + ? OP_CASTBOOL : e->to == PAW_TINT + ? OP_CASTINT : OP_CASTFLOAT; + + V->visit_expr(V, e->arg); + pawK_code_U(G->fs, op, from->adt.did); +} + static void code_func_decl(AstVisitor *V, FuncDecl *d) { FuncState *fs = V->state.G->fs; @@ -1024,7 +1066,7 @@ static void close_until_loop(FuncState *fs) // paths that doesn't hit this label may still need those locals. BlockState *outer = bs->outer; if (outer->is_loop) { - close_vars(fs, bs->level); + close_vars(fs, bs); return; } bs = outer; @@ -1092,11 +1134,12 @@ static void code_forbody(AstVisitor *V, Block *block, Op opinit, Op oploop) const int jump = code_jump(fs, opinit); const int loop = fs->pc; - // Enter a scope for the loop variable: if it is captured in a closure, - // the upvalue must be closed at the end of the iteration. + // Put the control variable in the same scope as any locals declared inside + // the loop. If the control variable is captured in a closure, the upvalue + // must be closed at the end of the iteration. enter_block(fs, &bs, block->scope, PAW_FALSE); code_var(G, PAW_FALSE); - V->visit_block_stmt(V, block); + V->visit_stmt_list(V, block->stmts, V->visit_stmt); leave_block(fs); // Continue statements jump here, right before the loop instruction. @@ -1120,10 +1163,7 @@ static void code_fornum_stmt(AstVisitor *V, ForStmt *s) code_forbody(V, s->block, OP_FORNUM0, OP_FORNUM); } -static void code_forin_stmt( - AstVisitor *V, - ForStmt *s) // TODO: forin would need to encode the type of object being - // iterated over. look into function call for loop? +static void code_forin_stmt(AstVisitor *V, ForStmt *s) { Generator *G = V->state.G; ForIn *forin = &s->forin; @@ -1148,14 +1188,31 @@ static void code_for_stmt(AstVisitor *V, ForStmt *s) leave_block(fs); } -static void code_index_expr(AstVisitor *V, Index *e) +// TODO: Not very nice, would be better to transform instantiations into another node type +static paw_Bool handle_templates(AstVisitor *V, Index *e) { Generator *G = V->state.G; AstType *target = a_type(e->target); if (a_is_func(target)) { code_instance_getter(V, e->type); + return PAW_TRUE; + } else if (a_is_adt(target)) { + AstDecl *decl = get_decl(G, target->adt.base); + StructDecl *d = &decl->struct_; + if (!d->is_struct) { + return PAW_TRUE; + } + } + return PAW_FALSE; +} + +static void code_index_expr(AstVisitor *V, Index *e) +{ + if (handle_templates(V, e)) { return; } + Generator *G = V->state.G; + AstType *target = a_type(e->target); paw_assert(e->elems->count == 1); V->visit_expr(V, e->target); V->visit_expr(V, e->elems->data[0]); @@ -1170,8 +1227,51 @@ static void code_selector_expr(AstVisitor *V, Selector *e) { Generator *G = V->state.G; V->visit_expr(V, e->target); - const VarInfo info = resolve_attr(G, a_type(e->target), e->name); - pawK_code_U(G->fs, OP_GETATTR, info.index); + if (e->is_index) { + pawK_code_U(G->fs, OP_GETTUPLE, e->index); + } else { + const VarInfo info = resolve_attr(G, a_type(e->target), e->name); + pawK_code_U(G->fs, OP_GETATTR, info.index); + } +} + +static void code_literal_pat(AstVisitor *V, AstLiteralPat *p) +{ + V->visit_expr(V, p->expr); +} + +static void code_path_pat(AstVisitor *V, AstPathPat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void code_tuple_pat(AstVisitor *V, AstTuplePat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void code_field_pat(AstVisitor *V, AstFieldPat *p) +{ + paw_unused(V); + paw_unused(p); +} + +static void code_struct_pat(AstVisitor *V, AstStructPat *p) +{ + Generator *G = V->state.G; + const int target = G->fs->level; + + paw_unused(p); +} + +static void code_variant_pat(AstVisitor *V, AstVariantPat *p) +{ + for (int i = 0; i < p->elems->count; ++i) { + AstPat *elem = p->elems->data[i]; + V->visit_pat(V, elem); + } } static void code_builtin(Generator *G) @@ -1199,11 +1299,13 @@ static void setup_pass(AstVisitor *V, Generator *G) V->visit_chain_expr = code_chain_expr; V->visit_unop_expr = code_unop_expr; V->visit_binop_expr = code_binop_expr; - V->visit_cond_expr = code_cond_expr; + V->visit_conversion_expr = code_conversion_expr; V->visit_call_expr = code_call_expr; V->visit_index_expr = code_index_expr; V->visit_selector_expr = code_selector_expr; V->visit_item_expr = code_item_expr; + V->visit_match_expr = code_match_expr; + V->visit_arm_expr = code_arm_expr; V->visit_block_stmt = code_block_stmt; V->visit_expr_stmt = code_expr_stmt; V->visit_decl_stmt = code_decl_stmt; @@ -1217,6 +1319,12 @@ static void setup_pass(AstVisitor *V, Generator *G) V->visit_func_decl = code_func_decl; V->visit_struct_decl = code_struct_decl; V->visit_field_decl = code_field_decl; + V->visit_literal_pat = code_literal_pat; + V->visit_path_pat = code_path_pat; + V->visit_tuple_pat = code_tuple_pat; + V->visit_field_pat = code_field_pat; + V->visit_struct_pat = code_struct_pat; + V->visit_variant_pat = code_variant_pat; AstList *prelude = V->ast->prelude; for (int i = 0; i < prelude->count; ++i) { diff --git a/src/debug.c b/src/debug.c index 2287224..4838a7e 100644 --- a/src/debug.c +++ b/src/debug.c @@ -86,6 +86,10 @@ const char *paw_op_name(Op op) return "COPY"; case OP_INITFIELD: return "INITFIELD"; + case OP_TRANSIT: + return "TRANSIT"; + case OP_MATCHVARIANT: + return "MATCHVARIANT"; case OP_POP: return "POP"; case OP_CLOSE: @@ -120,6 +124,10 @@ const char *paw_op_name(Op op) return "GETUPVALUE"; case OP_SETUPVALUE: return "SETUPVALUE"; + case OP_NEWTUPLE: + return "NEWTUPLE"; + case OP_NEWVARIANT: + return "NEWVARIANT"; case OP_NEWINSTANCE: return "NEWINSTANCE"; case OP_NEWVECTOR: @@ -140,8 +148,12 @@ const char *paw_op_name(Op op) return "UNOP"; case OP_BINOP: return "BINOP"; + case OP_GETTUPLE: + return "GETTUPLE"; case OP_GETATTR: return "GETATTR"; + case OP_SETTUPLE: + return "SETTUPLE"; case OP_SETATTR: return "SETATTR"; case OP_GETITEM: @@ -195,6 +207,12 @@ void paw_dump_opcode(OpCode opcode) case OP_INIT: printf("INIT\n"); break; + case OP_MATCHVARIANT: + printf("MATCHVARIANT\n"); + break; + case OP_TRANSIT: + printf("TRANSIT\n"); + break; case OP_RETURN: printf("RETURN\n"); break; @@ -237,6 +255,9 @@ void paw_dump_opcode(OpCode opcode) case OP_SETUPVALUE: printf("SETUPVALUE: %d\n", get_U(opcode)); break; + case OP_NEWTUPLE: + printf("NEWTUPLE\n"); + break; case OP_NEWINSTANCE: printf("NEWINSTANCE\n"); break; @@ -268,9 +289,15 @@ void paw_dump_opcode(OpCode opcode) printf("BINOP %s %d\n", paw_binop_name(get_A(opcode)), get_B(opcode)); break; + case OP_GETTUPLE: + printf("GETTUPLE %d\n", get_U(opcode)); + break; case OP_GETATTR: printf("GETATTR %d\n", get_U(opcode)); break; + case OP_SETTUPLE: + printf("SETTUPLE %d\n", get_U(opcode)); + break; case OP_SETATTR: printf("SETATTR %d\n", get_U(opcode)); break; @@ -313,9 +340,24 @@ void dump_aux(paw_Env *P, Proto *proto, Buffer *print) break; } + case OP_POP: { + pawL_add_fstring(P, print, " ; u = %d", get_U(opcode)); + break; + } + + case OP_MATCHVARIANT: { + pawL_add_fstring(P, print, " ; k = %d", get_U(opcode)); + break; + } + + case OP_TRANSIT: { + pawL_add_fstring(P, print, " ; n = %d", get_U(opcode)); + break; + } + case OP_CLOSE: { - pawL_add_fstring(P, print, " ; count = %d, close = %d", - get_A(opcode), get_B(opcode)); + pawL_add_fstring(P, print, " ; count = %d", + get_U(opcode)); break; } @@ -329,13 +371,15 @@ void dump_aux(paw_Env *P, Proto *proto, Buffer *print) break; } - case OP_NEWVECTOR: { - pawL_add_fstring(P, print, " ; %d elements", get_U(opcode)); + case OP_NEWVARIANT: { + pawL_add_fstring(P, print, " ; #%d", get_U(opcode)); break; } - case OP_NEWMAP: { - pawL_add_fstring(P, print, " ; %d items", get_U(opcode)); + case OP_NEWVECTOR: + case OP_NEWMAP: + case OP_NEWTUPLE: { + pawL_add_fstring(P, print, " ; %d values", get_U(opcode)); break; } @@ -511,27 +555,6 @@ void paw_stacktrace(paw_Env *P) pawL_push_result(P, &buf); } -// TODO: rename paw_dump_locals -void paw_dump_stack(paw_Env *P) -{ - CallFrame *cf = P->main.next; - while (cf != NULL) { - const Proto *func = cf->fn->p; - printf("Frame: %s\n", func->name->text); - for (int i = 0; i < func->ndebug; ++i) { - const struct LocalInfo info = func->v[i]; - const char *capture = info.captured ? "*" : ""; - const String *name = info.var.name; - const paw_Type code = info.var.code; - printf(" %3d: %s%s (%d)\n", i, name->text, capture, code); - } - if (cf == P->cf) { - break; - } - cf = cf->next; - } -} - void paw_dump_value(paw_Env *P, Value v, paw_Type type) { Buffer buf; diff --git a/src/debug.h b/src/debug.h index bfa8c69..361904b 100644 --- a/src/debug.h +++ b/src/debug.h @@ -10,7 +10,6 @@ const char *paw_op_name(Op op); void paw_dump_opcode(OpCode opcode); void paw_dump_source(paw_Env *P, Proto *proto); -void paw_dump_stack(paw_Env *P); void paw_stacktrace(paw_Env *P); void paw_dump_value(paw_Env *P, Value v, int type); void paw_dump_map(paw_Env *P, Map *m); diff --git a/src/env.c b/src/env.c index bab3c6e..f866921 100644 --- a/src/env.c +++ b/src/env.c @@ -25,15 +25,15 @@ int pawE_new_global(paw_Env *P, String *name, paw_Type type) { struct GlobalVec *gv = &P->gv; // enforce uniqueness for (int i = 0; i < gv->size; ++i) { - if (pawS_eq(name, gv->data[i].desc.name)) { + if (pawS_eq(name, gv->data[i].name)) { paw_assert(0); // FIXME } } pawM_grow(P, gv->data, gv->size, gv->alloc); const int i = gv->size++; GlobalVar *var = &gv->data[i]; - var->desc.name = name; - var->desc.code = type; + var->name = name; + var->type = type; v_set_0(&var->value); return i; } @@ -43,7 +43,7 @@ GlobalVar *pawE_find_global(paw_Env *P, String *name) struct GlobalVec *gv = &P->gv; for (int i = 0; i < gv->size; ++i) { GlobalVar *var = &gv->data[i]; - if (pawS_eq(name, var->desc.name)) { + if (pawS_eq(name, var->name)) { return var; } } diff --git a/src/env.h b/src/env.h index 7d84bf5..911f337 100644 --- a/src/env.h +++ b/src/env.h @@ -18,7 +18,7 @@ struct Jump; // call.c typedef enum DefKind { DEF_VAR, DEF_FUNC, - DEF_STRUCT, + DEF_ADT, DEF_FIELD, DEF_TYPE, } DefKind; @@ -96,10 +96,29 @@ enum { }; typedef struct GlobalVar { - VarDesc desc; + String *name; Value value; + paw_Type type; } GlobalVar; +struct GlobalList { + int alloc; + int count; + Value data[]; +}; + +struct BuiltinList { + int alloc; + int count; + Value data[]; +}; + +struct MethodList { + int alloc; + int count; + Value data[]; +}; + typedef struct paw_Env { StringTable strings; @@ -132,9 +151,6 @@ typedef struct paw_Env { // memory (a call to the 'alloc' field below returned NULL). Value mem_errmsg; - // TODO: At some point, the globals should go into a struct called Module. - // Make - // Module a paw object. struct GlobalVec { GlobalVar *data; int size; diff --git a/src/lex.c b/src/lex.c index 7fee809..e029b95 100644 --- a/src/lex.c +++ b/src/lex.c @@ -3,7 +3,6 @@ // LICENSE.md. See AUTHORS.md for a list of contributor names. #include "lex.h" #include "auxlib.h" -// #include "bigint.h" #include "gc_aux.h" #include "map.h" #include "mem.h" @@ -419,6 +418,8 @@ static Token advance(Lex *x) next(x); if (test_next(x, '=')) { token = T(TK_EQUALS2); + } else if (test_next(x, '>')) { + token = T(TK_FAT_ARROW); } break; case '&': @@ -439,12 +440,6 @@ static Token advance(Lex *x) token = T(TK_ARROW); } break; - case '?': - next(x); - if (test_next(x, '?')) { - token = T(TK_QUESTION2); - } - break; case ':': next(x); if (test_next(x, ':')) { @@ -474,15 +469,12 @@ static Token advance(Lex *x) } break; case '.': - save_and_next(x); // may be float + next(x); if (test_next(x, '.')) { if (test_next(x, '.')) { token = T(TK_DOT3); } lex_error(x); // '..' not allowed - } else if (ISDIGIT(x->c)) { - token = consume_number(x); - semi = PAW_TRUE; } break; case '/': diff --git a/src/lex.h b/src/lex.h index 3eac4b4..b046d95 100644 --- a/src/lex.h +++ b/src/lex.h @@ -20,7 +20,6 @@ enum MultiChar { // Multi-byte tokens: TK_DOT3, - TK_QUESTION2, TK_COLON2, TK_LESS2, TK_GREATER2, @@ -28,6 +27,7 @@ enum MultiChar { TK_EQUALS2, TK_PIPE2, TK_ARROW, + TK_FAT_ARROW, TK_LESS_EQ, TK_GREATER_EQ, TK_BANG_EQ, @@ -41,8 +41,10 @@ enum MultiChar { // Keywords (must be in this order): TK_FN, TK_TYPE, + TK_ENUM, TK_STRUCT, TK_GLOBAL, + TK_MATCH, TK_LET, TK_IF, TK_ELSE, @@ -55,6 +57,8 @@ enum MultiChar { TK_IN, TK_TRUE, TK_FALSE, + + TK_LIMIT // must be last }; typedef unsigned TokenKind; diff --git a/src/lib.h b/src/lib.h index 7c132b6..10cf04e 100644 --- a/src/lib.h +++ b/src/lib.h @@ -27,8 +27,8 @@ int pawL_load_nchunk(paw_Env *P, const char *name, const char *source, size_t length); int pawL_load_chunk(paw_Env *P, const char *name, const char *source); -#define L_GENERIC_MAX ARGC_MAX -#define L_PARAM_MAX ARGC_MAX +#define L_GENERIC_MAX PARAM_MAX +#define L_PARAM_MAX PARAM_MAX #define L_LIST_END INT_MIN #define L_SELF (INT_MIN + 1) diff --git a/src/opcode.h b/src/opcode.h index 8bdc1e2..dbfd78a 100644 --- a/src/opcode.h +++ b/src/opcode.h @@ -7,23 +7,27 @@ #include "paw.h" #ifndef UPVALUE_MAX -#define UPVALUE_MAX 64 +# define UPVALUE_MAX 64 #endif #ifndef LOCAL_MAX -#define LOCAL_MAX 1024 +# define LOCAL_MAX 1024 #endif -#ifndef ATTR_MAX -#define ATTR_MAX 4096 +#ifndef FIELD_MAX +# define FIELD_MAX 4096 #endif -#ifndef ARGC_MAX -#define ARGC_MAX 256 +#ifndef PARAM_MAX +# define PARAM_MAX 256 +#endif + +#ifndef ITEM_MAX +# define ITEM_MAX A_MAX #endif #ifndef JUMP_MAX -#define JUMP_MAX S_MAX +# define JUMP_MAX S_MAX #endif #define decode_jump(x) ((int)(x) - JUMP_MAX) @@ -73,6 +77,11 @@ typedef uint32_t OpCode; +// match e { +// E::X(x) => x, +// E::X('x') => 'x', +// } + // clang-format off // // Opcode format: Each instruction is packed into a 32-bit unsigned integer (OpCode) @@ -96,12 +105,13 @@ OP_PUSHFALSE,// - - false - OP_PUSHCONST,// U - K[u] - OP_PUSHSTRUCT,// U - C[u] - -OP_POP,// - v - - +OP_POP,// U vu..v1 - - +OP_CLOSE,// U vu..v1 - close stack to vu OP_COPY,// - v v v - -OP_CLOSE,// A B v_a..v_1 - if b, close stack to v_a OP_RETURN,// - f..v v closes stack to f +OP_TRANSIT,// U vu..v1 v1 closes stack to vu -OP_CLOSURE,// A B v_b..v_1 f captures v_u..v_1 in f = P[a] +OP_CLOSURE,// A B vb..v1 f captures vu..v1 in f = P[a] OP_INVOKE,// OP_JUMP,// S - - pc += S @@ -117,10 +127,17 @@ OP_SETLOCAL,// U v - L[u] = v OP_GETUPVALUE,// U - Up[u] - OP_SETUPVALUE,// U v - Up[u] = v +OP_MATCHVARIANT,// U v disc(v)==u - +OP_UNPACKTUPLE,// U v vu..v1 - +OP_UNPACKINSTANCE,// U v vu..v1 - +OP_UNPACKVARIANT,// U v vu..v1 - + +OP_NEWVARIANT,// A B vb..v1 a(vb..v1) - +OP_NEWTUPLE,// U vu..v1 (vu..v1) - OP_NEWINSTANCE,// U - v v = new instance of class C[u] OP_INITFIELD,// U i v i i.fields[u] = v -OP_NEWVECTOR,// U v_u..v_1 [v_u..v_1] - -OP_NEWMAP,// U v_2n..v_1 {v_2n..v_1} - +OP_NEWVECTOR,// U vu..v1 [vu..v1] - +OP_NEWMAP,// U v_2n..v1 {v_2n..v1} - OP_FORNUM0,// S *-*-*-*-*-*-*-*-* see notes *-*-*-*-*-*-*-*-* OP_FORNUM,// S *-*-*-*-*-*-*-*-* see notes *-*-*-*-*-*-*-*-* @@ -136,12 +153,14 @@ OP_CASTBOOL,// U v bool(v) - OP_CASTINT,// U v int(v) - OP_CASTFLOAT,// U v float(v) - -OP_VARARG,// A B v_u..v_1 [v_u..v_1] - +OP_VARARG,// A B vu..v1 [vu..v1] - OP_INIT, -OP_CALL,// U f v_u..v_1 v v = f(v_u..v_1) +OP_CALL,// U f vu..v1 v v = f(vu..v1) -OP_GETATTR,// U v v.fields[u] - -OP_SETATTR,// U v x - v.fields[u]=x +OP_GETTUPLE,// U v v.u - +OP_GETATTR,// U v v.u - +OP_SETTUPLE,// U v x - v.u=x +OP_SETATTR,// U v x - v.u=x OP_GETITEM,// - v i v[i] - OP_SETITEM,// - v i x - v[i]=x diff --git a/src/parse.c b/src/parse.c index 2d11d56..e8d345e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -28,14 +28,20 @@ #define new_expr(lex, kind) pawA_new_expr((lex)->pm->ast, kind) #define new_decl(lex, kind) pawA_new_decl((lex)->pm->ast, kind) #define new_stmt(lex, kind) pawA_new_stmt((lex)->pm->ast, kind) +#define new_pat(lex, kind) pawA_new_pat((lex)->pm->ast, kind) #define new_list(lex) pawA_list_new((lex)->pm->ast) #define list_push(lex, list, node) pawA_list_push((lex)->pm->ast, &(list), node) // recursive non-terminals +static AstPat *pattern(Lex *lex); static AstExpr *expression(Lex *lex, unsigned prec); static AstStmt *statement(Lex *lex); -#define expression0(x) expression(x, 0) + +static AstExpr *expression0(Lex *lex) +{ + return expression(lex, 0); +} static void expected_symbol(Lex *lex, const char *want) { @@ -88,8 +94,6 @@ typedef enum { INFIX_SHR, // >> INFIX_AND, // && INFIX_OR, // || - INFIX_COND, // ??:: - INFIX_COALESCE, // ?: NINFIX } InfixOp; @@ -101,24 +105,38 @@ static const struct { uint8_t left; uint8_t right; } kInfixPrec[NINFIX] = { - [INFIX_MUL] = {13, 13}, [INFIX_DIV] = {13, 13}, - [INFIX_MOD] = {13, 13}, [INFIX_ADD] = {12, 12}, - [INFIX_SUB] = {12, 12}, [INFIX_SHL] = {10, 10}, - [INFIX_SHR] = {10, 10}, [INFIX_BAND] = {9, 9}, - [INFIX_BXOR] = {8, 8}, [INFIX_BOR] = {7, 7}, - [INFIX_IN] = {6, 6}, [INFIX_LT] = {6, 6}, - [INFIX_LE] = {6, 6}, [INFIX_GT] = {6, 6}, - [INFIX_GE] = {6, 6}, [INFIX_EQ] = {5, 5}, - [INFIX_NE] = {5, 5}, [INFIX_AND] = {4, 4}, - [INFIX_OR] = {3, 3}, [INFIX_COALESCE] = {2, 2}, - [INFIX_COND] = {1, 0}, // right-associative + [INFIX_MUL] = {13, 13}, + [INFIX_DIV] = {13, 13}, + [INFIX_MOD] = {13, 13}, + [INFIX_ADD] = {12, 12}, + [INFIX_SUB] = {12, 12}, + [INFIX_SHL] = {10, 10}, + [INFIX_SHR] = {10, 10}, + [INFIX_BAND] = {9, 9}, + [INFIX_BXOR] = {8, 8}, + [INFIX_BOR] = {7, 7}, + [INFIX_IN] = {6, 6}, + [INFIX_LT] = {6, 6}, + [INFIX_LE] = {6, 6}, + [INFIX_GT] = {6, 6}, + [INFIX_GE] = {6, 6}, + [INFIX_EQ] = {5, 5}, + [INFIX_NE] = {5, 5}, + [INFIX_AND] = {4, 4}, + [INFIX_OR] = {3, 3}, }; static const uint8_t kUnOpPrecedence = 14; -static unsigned left_prec(InfixOp op) { return kInfixPrec[op].left; } +static unsigned left_prec(InfixOp op) +{ + return kInfixPrec[op].left; +} -static unsigned right_prec(InfixOp op) { return kInfixPrec[op].right; } +static unsigned right_prec(InfixOp op) +{ + return kInfixPrec[op].right; +} static UnOp get_unop(TokenKind kind) { @@ -161,8 +179,6 @@ static InfixOp get_infixop(TokenKind kind) return INFIX_BOR; case TK_IN: return INFIX_IN; - case TK_QUESTION2: - return INFIX_COND; case TK_EQUALS2: return INFIX_EQ; case TK_LESS2: @@ -211,7 +227,10 @@ static paw_Bool test_next(Lex *lex, TokenKind kind) } // Eat a semicolon, if one exists -static void semicolon(Lex *lex) { test_next(lex, ';'); } +static void semicolon(Lex *lex) +{ + test_next(lex, ';'); +} static String *parse_name(Lex *lex) { @@ -245,56 +264,124 @@ static AstExpr *emit_bool(Lex *lex, paw_Bool b) static AstExpr *type_expr(Lex *lex); -static void parse_type_list(Lex *lex, AstList *list) +static AstDecl *vfield_decl(Lex *lex) +{ + AstDecl *r = new_decl(lex, DECL_FIELD); + r->field.name = NULL; + r->field.tag = type_expr(lex); + return r; +} + +#define make_list_parser(name, a, b, limit, what, func, T) \ + static void parse_ ## name ## _list(Lex *lex, AstList **plist, int line) \ + { \ + do { \ + if (test(lex, b)) { \ + break; \ + } else if ((*plist)->count == (limit)) { \ + limit_error(lex, what, (limit)); \ + } \ + T *next = (func)(lex); \ + list_push(lex, *plist, next); \ + } while (test_next(lex, ',')); \ + delim_next(lex, b, a, line); \ + } +make_list_parser(arg, '(', ')', LOCAL_MAX, "arguments", expression0, AstExpr) +make_list_parser(vfield, '(', ')', LOCAL_MAX, "variant fields", vfield_decl, AstDecl) +make_list_parser(type, '[', ']', LOCAL_MAX, "type arguments", type_expr, AstExpr) + +static AstList *vfield_list(Lex *lex, int line) { ++lex->expr_depth; - do { - if (list->count == ARGC_MAX) { - limit_error(lex, "generic type arguments", ARGC_MAX); - } - AstExpr *type = type_expr(lex); - list_push(lex, list, type); - } while (test_next(lex, ',')); + AstList *list = new_list(lex); + parse_vfield_list(lex, &list, line); + --lex->expr_depth; + return list; +} + +static AstList *type_list(Lex *lex, int line) +{ + ++lex->expr_depth; + AstList *list = new_list(lex); + parse_type_list(lex, &list, line); --lex->expr_depth; + return list; } -static AstList *maybe_type_args(Lex *lex) +static AstList *type_args(Lex *lex) { - AstList *types = new_list(lex); const int line = lex->line; if (test_next(lex, '[')) { // type arguments (requires at least 1) - parse_type_list(lex, types); - delim_next(lex, ']', '[', line); + return type_list(lex, line); } - return types; + return new_list(lex); } -static AstList *parse_params(Lex *lex, int line) +static void set_unit(Lex *lex, AstExpr *pe) { - AstList *list = new_list(lex); + pe->type_name.kind = EXPR_TYPENAME; + pe->type_name.name = pawE_cstr(env(lex), CSTR_UNIT); + pe->type_name.args = new_list(lex); +} + +static AstExpr *unit_type(Lex *lex) +{ + AstExpr *r = new_expr(lex, EXPR_TYPENAME); + set_unit(lex, r); + return r; +} + +static void parse_type_expr(Lex *lex, AstExpr *pe); + +static void parse_typelist(Lex *lex, AstExpr *pe, int line) +{ + AstExpr *first = new_expr(lex, 0); + *first = *pe; + + pe->typelist.kind = EXPR_TYPELIST; + AstList *elems = new_list(lex); + list_push(lex, elems, first); + pe->typelist.types = elems; + + do { + if (test(lex, ')')) { + break; + } else if (elems->count == FIELD_MAX) { + limit_error(lex, "tuple elements", FIELD_MAX); + } + AstExpr *type = type_expr(lex); + list_push(lex, elems, type); + } while (test_next(lex, ',')); + delim_next(lex, ')', '(', line); +} + +static void parse_paren_type(Lex *lex, AstExpr *pe) +{ + const int line = lex->last_line; if (test_next(lex, ')')) { - return list; + set_unit(lex, pe); + return; + } + parse_type_expr(lex, pe); + if (test_next(lex, ',')) { + parse_typelist(lex, pe, line); } - parse_type_list(lex, list); - delim_next(lex, ')', '(', line); - return list; } static void parse_signature(Lex *lex, AstExpr *pe) { const int line = lex->line; - pe->func.kind = EXPR_FUNC_TYPE; + pe->func.kind = EXPR_FUNCTYPE; check_next(lex, '('); - - // function parameters - pe->func.params = parse_params(lex, line); - - // return type annotation + pe->func.params = new_list(lex); + if (!test_next(lex, ')')) { + parse_arg_list(lex, &pe->func.params, line); + } if (test_next(lex, TK_ARROW)) { - pe->func.return_ = type_expr(lex); + pe->func.result = type_expr(lex); } else { - pe->func.return_ = emit_unit(lex); + pe->func.result = emit_unit(lex); } } @@ -302,27 +389,26 @@ static void parse_named_type(Lex *lex, AstExpr *pe) { String *name = parse_name(lex); pe->type_name.name = name; - pe->type_name.kind = EXPR_TYPE_NAME; + pe->type_name.kind = EXPR_TYPENAME; // list of concrete types between '[' and ']' - pe->type_name.args = maybe_type_args(lex); + pe->type_name.args = type_args(lex); } -static AstExpr *type_expr(Lex *lex) +static void parse_type_expr(Lex *lex, AstExpr *pe) { - AstExpr *r = new_expr(lex, 0 /* set in parse_*() */); - if (test_next(lex, TK_FN)) { - parse_signature(lex, r); + if (test_next(lex, '(')) { + parse_paren_type(lex, pe); + } else if (test_next(lex, TK_FN)) { + parse_signature(lex, pe); } else { - parse_named_type(lex, r); + parse_named_type(lex, pe); } - return r; } -static AstExpr *unit_type(Lex *lex) +static AstExpr *type_expr(Lex *lex) { - AstExpr *r = new_expr(lex, EXPR_TYPE_NAME); - r->type_name.name = pawE_cstr(env(lex), CSTR_UNIT); - r->type_name.args = new_list(lex); + AstExpr *r = new_expr(lex, 0); + parse_type_expr(lex, r); return r; } @@ -377,17 +463,100 @@ static AstDecl *var_decl(Lex *lex, int line, paw_Bool global) return r; } -static AstList *expr_list1(Lex *lex, const char *what) +static AstList *parse_path(Lex *lex) { - AstList *list = new_list(lex); + Ast *ast = lex->pm->ast; + AstList *path = new_list(lex); do { - if (list->count == ARGC_MAX) { - limit_error(lex, what, ARGC_MAX); + if (path->count == LOCAL_MAX) { + limit_error(lex, "path segments", LOCAL_MAX); } - AstExpr *next = expression0(lex); - list_push(lex, list, next); - } while (test_next(lex, ',')); - return list; + String *name = parse_name(lex); + AstList *args = type_args(lex); + pawA_path_push(ast, &path, name, args); + } while (test_next(lex, TK_COLON2)); + return path; +} + +static AstPat *vfield_pat(Lex *lex) +{ + AstPat *r = new_pat(lex, AST_PAT_FIELD); + r->field.pat = pattern(lex); + return r; +} + +static AstPat *new_ident_pat(Lex *lex, String *name) +{ + Ast *ast = lex->pm->ast; + AstPat *r = new_pat(lex, AST_PAT_PATH); + AstList *path = new_list(lex); + AstList *args = new_list(lex); + pawA_path_push(ast, &path, name, args); + r->path.path = path; + return r; +} + +static AstPat *sfield_pat(Lex *lex) +{ + AstPat *r = new_pat(lex, AST_PAT_FIELD); + r->field.name = parse_name(lex); + if (test_next(lex, ':')) { + r->field.pat = pattern(lex); + } else { + // binds field to variable of same name + r->field.pat = new_ident_pat(lex, r->field.name); + } + return r; +} + +static AstDecl *generic_param(Lex *lex) +{ + AstDecl *r = new_decl(lex, DECL_GENERIC); + r->generic.name = parse_name(lex); + return r; +} + +make_list_parser(index, '[', ']', LOCAL_MAX, "elements", expression0, AstExpr) +make_list_parser(param, '(', ')', LOCAL_MAX, "parameters", param_decl, AstDecl) +make_list_parser(generic, '[', ']', LOCAL_MAX, "generics", generic_param, AstDecl) +make_list_parser(vfield_pat, '(', ')', LOCAL_MAX, "variant fields", vfield_pat, AstPat) +make_list_parser(sfield_pat, '{', '}', LOCAL_MAX, "struct fields", sfield_pat, AstPat) + +static AstPat *compound_pat(Lex *lex) +{ + AstPat *r = new_pat(lex, AST_PAT_PATH); + AstList *path = parse_path(lex); + AstList *fields = new_list(lex); + if (test_next(lex, '(')) { + parse_vfield_pat_list(lex, &fields, r->hdr.line); + r->variant.kind = AST_PAT_VARIANT; + r->variant.path = path; + r->variant.elems = fields; + } else if (test_next(lex, '{')) { + parse_sfield_pat_list(lex, &fields, r->hdr.line); + r->struct_.kind = AST_PAT_STRUCT; + r->struct_.path = path; + r->struct_.fields = fields; + } else { + r->path.path = path; + } + return r; +} + +static AstPat *literal_pat(Lex *lex) +{ + AstPat *r = new_pat(lex, AST_PAT_LITERAL); + r->literal.expr = expression0(lex); + return r; +} + +static AstPat *pattern(Lex *lex) +{ + if (test(lex, TK_NAME)) { + return compound_pat(lex); + } else { + return literal_pat(lex); + } } static AstExpr *composite_lit(Lex *, AstExpr *); @@ -408,33 +577,7 @@ static AstExpr *item_expr(Lex *lex) return r; } -static AstList *item_list0(Lex *lex, const char *what) -{ - AstList *list = new_list(lex); - do { - if (test(lex, '}')) { - break; - } else if (list->count == LOCAL_MAX) { - limit_error(lex, what, LOCAL_MAX); - } - AstExpr *next = item_expr(lex); - list_push(lex, list, next); - } while (test_next(lex, ',')); - return list; -} - -static AstList *arguments(Lex *lex) -{ - const int line = lex->line; - skip(lex); // '(' token - - if (test_next(lex, ')')) { - return new_list(lex); // empty - } - AstList *list = expr_list1(lex, "function parameters"); - delim_next(lex, ')', '(', line); - return list; -} +make_list_parser(item, '{', '}', LOCAL_MAX, "items", item_expr, AstExpr) // Parse an identifier static AstExpr *name_expr(Lex *lex) @@ -501,45 +644,25 @@ static AstExpr *paren_expr(Lex *lex) // Just parse and return the expression contained within the parenthesis. // There is no need for an extra node type. const int line = lex->line; - AstExpr *elems = NULL; - int nelems = 0; skip(lex); // '(' token - if (!test(lex, ')')) { - ++lex->expr_depth; - elems = expression0(lex); - --lex->expr_depth; - if (test_next(lex, ')')) { - return elems; - } + if (test_next(lex, ')')) { + const Value v = {.p = NULL}; + return new_basic_lit(lex, v, PAW_TUNIT); } - pawX_error(lex, "TODO: tuples are not yet implemented"); - return NULL; - - // if (!test(lex, ')')) { - // elems = expression0(lex); - // if (test_next(lex, ')')) { - // // Found a normal parenthesized exprssion: "(" AstExpr ")". - // return elems; - // } - // // // Expect an n-tuple (1-tuple requires a trailing ','). - // // while (test_next(lex, ',')) { - // // if (nelems > UINT8_MAX) { - // // limit_error(lex, "tuple elements", UINT8_MAX); - // // } - // // elems->hdr.next = expression0(lex); - // // elems = elems->hdr.next; - // // ++nelems; - // // } - // } - // --lex->expr_depth; - // AstExpr *result = new_expr(lex, EXPR_LITERAL); - // LiteralExpr *lit = &result->literal; - // TupleLit *r = &lit->tuple; - // lit->line = line; - // r->elems = elems; - // r->nelems = nelems; - // delim_next(lex, ')', '(', line); - // return result; + ++lex->expr_depth; + AstExpr *expr = expression0(lex); + --lex->expr_depth; + if (test_next(lex, ')')) { + return expr; + } + AstExpr *r = new_expr(lex, EXPR_LITERAL); + check_next(lex, ','); + AstList *elems = new_list(lex); + list_push(lex, elems, expr); + parse_arg_list(lex, &elems, line); + r->literal.lit_kind = LIT_TUPLE; + r->literal.tuple.elems = elems; + return r; } static paw_Bool end_of_block(Lex *lex) @@ -564,62 +687,14 @@ static AstList *stmt_list(Lex *lex) return list; } -static AstExpr *array_expr(Lex *lex) -{ - // AstExpr *result = new_expr(lex, EXPR_ARRAY); - // ArrayExpr *r = &result->array; - // const int line = lex->line; - // skip(lex); // '[' token - // - // int nitems = 0; - // AstExpr *items = r->items; - // do { - // if (test(lex, ']')) { - // break; - // } else if (nitems == LOCAL_MAX) { - // limit_error(lex, "array elements", LOCAL_MAX); - // } - // items->next = expression0(lex); - // items = items->next; - // ++nitems; - // } while (test_next(lex, ',')); - // delim_next(lex, ']', '[', line); - // return result; -} - -static AstExpr *map_expr(Lex *lex) -{ - // const int line = lex->line; - // skip(lex); // '{' token - // AstExpr *result = new_expr(lex, EXPR_MAP); - // MapExpr *r = &result->map; - // - // NodeVec *items = &r->items; - // do { - // if (test(lex, '}')) { - // break; - // } else if (items->size > LOCAL_MAX - 2) { - // limit_error(lex, "map items", LOCAL_MAX); - // } - // push_node(lex, items, expression0(lex)); - // check_next(lex, ':'); - // push_node(lex, items, expression0(lex)); - // } while (test_next(lex, ',')); - // delim_next(lex, '}', '{', line); - // return result; - return NULL; -} - static AstExpr *index_expr(Lex *lex, AstExpr *target) { AstExpr *result = new_expr(lex, EXPR_INDEX); Index *r = &result->index; - const int line = lex->line; skip(lex); // '[' token - r->target = target; - r->elems = expr_list1(lex, "bracketed terms"); - delim_next(lex, ']', '[', line); + r->elems = new_list(lex); + parse_index_list(lex, &r->elems, r->line); return result; } @@ -631,42 +706,79 @@ static AstExpr *composite_lit(Lex *lex, AstExpr *target) lit->lit_kind = LIT_COMPOSITE; CompositeLit *r = &lit->comp; skip(lex); // '{' token - r->items = item_list0(lex, "items"); + r->items = new_list(lex); + parse_item_list(lex, &r->items, lit->line); r->target = target; - delim_next(lex, '}', '{', lit->line); return result; } static AstExpr *selector_expr(Lex *lex, AstExpr *target) { - skip(lex); // '.' token AstExpr *r = new_expr(lex, EXPR_SELECTOR); + skip(lex); // '.' token r->selector.target = target; - r->selector.name = parse_name(lex); + if (test(lex, TK_NAME)) { + r->selector.name = parse_name(lex); + } else if (test(lex, TK_INTEGER)) { + r->selector.index = v_int(lex->t.value); + r->selector.is_index = PAW_TRUE; + skip(lex); // integer token + } return r; } static AstExpr *access_expr(Lex *lex, AstExpr *target) { - skip(lex); // '::' token AstExpr *r = new_expr(lex, EXPR_ACCESS); + skip(lex); // '::' token r->access.target = target; r->access.name = parse_name(lex); return r; } +static paw_Bool equals_cstr(Lex *lex, const AstIdent *ident, unsigned cstr) +{ + return pawS_eq(ident->name, pawE_cstr(env(lex), cstr)); +} + +static paw_Bool try_conversion(Lex *lex, AstExpr *target, AstExpr *r) +{ + if (a_kind(target) != EXPR_NAME) { + return PAW_FALSE; + } + AstIdent *ident = &target->name; + if (equals_cstr(lex, ident, CSTR_BOOL)) { + r->conv.to = PAW_TBOOL; + } else if (equals_cstr(lex, ident, CSTR_INT)) { + r->conv.to = PAW_TINT; + } else if (equals_cstr(lex, ident, CSTR_FLOAT)) { + r->conv.to = PAW_TFLOAT; + } else { + return PAW_FALSE; + } + const int line = lex->last_line; + r->conv.kind = EXPR_CONVERSION; + r->conv.arg = expression0(lex); + delim_next(lex, ')', '(', line); + return PAW_TRUE; +} + static AstExpr *call_expr(Lex *lex, AstExpr *target) { - AstExpr *result = new_expr(lex, EXPR_CALL); - CallExpr *r = &result->call; - r->args = arguments(lex); - r->target = target; - return result; + AstExpr *r = new_expr(lex, EXPR_CALL); + skip(lex); // '(' token + if (try_conversion(lex, target, r)) { + return r; + } + r->call.target = target; + r->call.args = new_list(lex); + parse_arg_list(lex, &r->call.args, r->call.line); + return r; } static AstExpr *chain_expr(Lex *lex, AstExpr *target) { - AstExpr *result = new_expr(lex, EXPR_UNOP); + AstExpr *result = new_expr(lex, EXPR_CHAIN); ChainExpr *r = &result->chain; r->target = target; skip(lex); // '?' token @@ -675,23 +787,10 @@ static AstExpr *chain_expr(Lex *lex, AstExpr *target) static AstList *parameters(Lex *lex) { - AstList *list = new_list(lex); const int line = lex->line; check_next(lex, '('); - - if (!test_next(lex, ')')) { - do { - if (list->count == ARGC_MAX) { - limit_error(lex, "function parameters", ARGC_MAX); - } else if (!test(lex, TK_NAME)) { - expected_symbol(lex, "name"); - } - // parse function parameter of form 'name: type' - AstDecl *next = param_decl(lex); - list_push(lex, list, next); - } while (test_next(lex, ',')); - delim_next(lex, ')', '(', line); - } + AstList *list = new_list(lex); + parse_param_list(lex, &list, line); return list; } @@ -706,6 +805,39 @@ static Block *block(Lex *lex) return r; } +static AstExpr *match_arm(Lex *lex) +{ + AstExpr *r = new_expr(lex, EXPR_MATCHARM); + r->arm.guard = pattern(lex); + if (test_next(lex, TK_IF)) { + r->arm.cond = expression0(lex); + } + check_next(lex, TK_FAT_ARROW); + r->arm.value = expression0(lex); + return r; +} + +static AstExpr *basic_expr(Lex *lex); + +static AstExpr *match_expr(Lex *lex) +{ + const int line = lex->line; + AstExpr *r = new_expr(lex, EXPR_MATCH); + skip(lex); // 'match' token + r->match.target = basic_expr(lex); + r->match.arms = new_list(lex); + check_next(lex, '{'); + do { + if (test(lex, '}')) { + break; + } + AstExpr *arm = match_arm(lex); + list_push(lex, r->match.arms, arm); + } while (test_next(lex, ',')); + delim_next(lex, '}', '{', line); + return r; +} + static AstExpr *primary_expr(Lex *lex) { switch (lex->t.kind) { @@ -718,10 +850,6 @@ static AstExpr *primary_expr(Lex *lex) skip(lex); // string token return new_basic_lit(lex, v, PAW_TSTRING); } - // case '[': - // return array_expr(lex); - // case '{': - // return map_expr(lex); case TK_FN: return type_expr(lex); default: @@ -744,11 +872,9 @@ static AstExpr *suffixed_expr(Lex *lex) case '.': e = selector_expr(lex, e); break; - // TODO: Change syntax of conditional expr so that this will - // work - // case TK_COLON2: - // e = access_expr(lex, e); - // break; + case TK_COLON2: + e = access_expr(lex, e); + break; case '[': e = index_expr(lex, e); break; @@ -788,6 +914,8 @@ static AstExpr *simple_expr(Lex *lex) case TK_FLOAT: expr = new_basic_lit(lex, lex->t.value, PAW_TFLOAT); break; + case TK_MATCH: + return match_expr(lex); default: return suffixed_expr(lex); } @@ -825,26 +953,13 @@ static AstExpr *logical_expr(Lex *lex, AstExpr *lhs, paw_Bool is_and) return result; } -static AstExpr *cond_expr(Lex *lex, AstExpr *lhs) -{ - skip(lex); // '??' token - AstExpr *result = new_expr(lex, EXPR_COND); - CondExpr *r = &result->cond; - r->cond = lhs; - r->lhs = expression(lex, right_prec(INFIX_COND)); - check_next(lex, TK_COLON2); - r->rhs = expression0(lex); - return result; -} - static AstExpr *infix_expr(Lex *lex, AstExpr *lhs, unsigned op) { switch (op) { case INFIX_AND: + return logical_expr(lex, lhs, PAW_TRUE); case INFIX_OR: - return logical_expr(lex, lhs, op == INFIX_AND); - case INFIX_COND: - return cond_expr(lex, lhs); + return logical_expr(lex, lhs, PAW_FALSE); default: return binop_expr(lex, op, lhs); } @@ -863,7 +978,6 @@ static AstExpr *subexpr(Lex *lex, unsigned prec) return expr; } -// TODO static AstExpr *expression(Lex *lex, unsigned prec) { return subexpr(lex, prec); @@ -961,19 +1075,17 @@ static AstStmt *for_stmt(Lex *lex) static AstStmt *while_stmt(Lex *lex) { - AstStmt *result = new_stmt(lex, STMT_WHILE); - WhileStmt *r = &result->while_; + AstStmt *r = new_stmt(lex, STMT_WHILE); skip(lex); // 'while' token - - r->cond = basic_expr(lex); - r->block = block(lex); - return result; + r->while_.cond = basic_expr(lex); + r->while_.block = block(lex); + return r; } static AstStmt *dowhile_stmt(Lex *lex) { - skip(lex); // 'do' token AstStmt *r = new_stmt(lex, STMT_DOWHILE); + skip(lex); // 'do' token r->while_.block = block(lex); check_next(lex, TK_WHILE); r->while_.cond = basic_expr(lex); @@ -982,56 +1094,40 @@ static AstStmt *dowhile_stmt(Lex *lex) static AstStmt *return_stmt(Lex *lex) { - AstStmt *result = new_stmt(lex, STMT_RETURN); - ReturnStmt *r = &result->return_; + AstStmt *r = new_stmt(lex, STMT_RETURN); skip(lex); // 'return' token if (end_of_block(lex) || test(lex, ';')) { - r->expr = NULL; + r->return_.expr = NULL; } else { - r->expr = expression0(lex); + r->return_.expr = expression0(lex); } - // NOTE: The construct 'return [expr] [`;`]' must be followed by the TODO: - // auto semicolon insertion fixes this - // end of the block. This is necessary because the semicolon is could - // relax restriction, make it easier to 'prototype' in paw optional, - // and we cannot easily tell if it was intended to go before or after - // the - // '[expr]' part. semicolon(lex); - return result; + return r; } static AstStmt *label_stmt(Lex *lex, LabelKind kind) { - AstStmt *result = new_stmt(lex, STMT_LABEL); - LabelStmt *r = &result->label; - r->label = kind; + AstStmt *r = new_stmt(lex, STMT_LABEL); skip(lex); // 'break' or 'continue' token + r->label.label = kind; semicolon(lex); - return result; + return r; } -static AstList *maybe_type_param(Lex *lex) +static AstList *type_param(Lex *lex) { const int line = lex->line; - AstList *list = new_list(lex); - if (!test_next(lex, '[')) { + if (test_next(lex, '[')) { + ++lex->expr_depth; + AstList *list = new_list(lex); + parse_generic_list(lex, &list, line); + --lex->expr_depth; + if (list->count == 0) { + pawX_error(lex, "empty generic parameters"); + } return list; - } else if (test_next(lex, ']')) { - pawX_error(lex, "empty generic parameters"); } - ++lex->expr_depth; - do { - if (list->count == ARGC_MAX) { - limit_error(lex, "generic type parameters", ARGC_MAX); - } - AstDecl *r = new_decl(lex, DECL_GENERIC); - r->generic.name = parse_name(lex); - list_push(lex, list, r); - } while (test_next(lex, ',')); - delim_next(lex, ']', '[', line); - --lex->expr_depth; - return list; + return new_list(lex); } static AstDecl *function(Lex *lex, String *name, FuncKind kind) @@ -1039,9 +1135,9 @@ static AstDecl *function(Lex *lex, String *name, FuncKind kind) AstDecl *r = new_decl(lex, DECL_FUNC); r->func.name = name; r->func.fn_kind = kind; - r->func.generics = maybe_type_param(lex); + r->func.generics = type_param(lex); r->func.params = parameters(lex); - r->func.return_ = ret_annotation(lex); + r->func.result = ret_annotation(lex); r->func.body = block(lex); r->func.monos = new_list(lex); return r; @@ -1057,34 +1153,77 @@ static AstDecl *func_decl(Lex *lex, int line, paw_Bool global) return r; } -static AstDecl *field_decl(Lex *lex, String *name) +static AstDecl *variant_decl(Lex *lex, int index) { - AstDecl *r = new_decl(lex, DECL_FIELD); - r->field.name = name; - r->field.tag = expect_annotation(lex, "field", r->field.name); - semicolon(lex); + AstDecl *r = new_decl(lex, DECL_VARIANT); + r->variant.name = parse_name(lex); + r->variant.fields = new_list(lex); + r->variant.index = index; + + const int line = lex->line; + if (test_next(lex, '(')) { + r->variant.fields = vfield_list(lex, line); + } return r; } -static AstDecl *attr_decl(Lex *lex) +static void parse_variant_list(Lex *lex, AstList **plist, int line) { - String *name = v_string(lex->t.value); - skip(lex); // name token - return field_decl(lex, name); + do { + if (test(lex, '}')) { + break; + } else if ((*plist)->count == LOCAL_MAX) { + limit_error(lex, "variants", LOCAL_MAX); + } + AstDecl *next = variant_decl(lex, (*plist)->count); + list_push(lex, *plist, next); + } while (test_next(lex, ',')); + delim_next(lex, '}', '{', line); } -static void struct_body(Lex *lex, StructDecl *struct_) +static void enum_body(Lex *lex, StructDecl *struct_) { const int line = lex->line; check_next(lex, '{'); + ++lex->expr_depth; + struct_->fields = new_list(lex); + parse_variant_list(lex, &struct_->fields, line); + --lex->expr_depth; +} + +static AstDecl *enum_decl(Lex *lex, paw_Bool global) +{ + skip(lex); // 'enum' token + AstDecl *r = new_decl(lex, DECL_STRUCT); + r->struct_.is_global = global; + r->struct_.is_struct = PAW_FALSE; + r->struct_.name = parse_name(lex); + r->struct_.generics = type_param(lex); + enum_body(lex, &r->struct_); + r->struct_.monos = new_list(lex); + return r; +} + +static AstDecl *field_decl(Lex *lex) +{ + AstDecl *r = new_decl(lex, DECL_FIELD); + r->field.name = parse_name(lex); + r->field.tag = expect_annotation(lex, "field", r->field.name); + semicolon(lex); + return r; +} + +static void struct_body(Lex *lex, StructDecl *struct_) +{ + const int line = lex->line; + check_next(lex, '{'); struct_->fields = new_list(lex); while (!test(lex, '}')) { - check(lex, TK_NAME); - AstDecl *next = attr_decl(lex); if (struct_->fields->count == LOCAL_MAX) { limit_error(lex, "fields", LOCAL_MAX); } + AstDecl *next = field_decl(lex); list_push(lex, struct_->fields, next); } delim_next(lex, '}', '{', line); @@ -1095,11 +1234,11 @@ static AstDecl *struct_decl(Lex *lex, paw_Bool global) skip(lex); // 'struct' token AstDecl *r = new_decl(lex, DECL_STRUCT); r->struct_.is_global = global; + r->struct_.is_struct = PAW_TRUE; r->struct_.name = parse_name(lex); - r->struct_.generics = maybe_type_param(lex); + r->struct_.generics = type_param(lex); struct_body(lex, &r->struct_); r->struct_.monos = new_list(lex); - semicolon(lex); return r; } @@ -1109,7 +1248,7 @@ static AstDecl *type_decl(Lex *lex) skip(lex); // 'type' token r->type.name = parse_name(lex); - r->type.generics = maybe_type_param(lex); + r->type.generics = type_param(lex); check_next(lex, '='); @@ -1127,8 +1266,9 @@ static AstDecl *global_decl(Lex *lex) const int line = lex->line; skip(lex); // 'global' token if (test(lex, TK_FN)) { - skip(lex); // 'fn' token return func_decl(lex, line, PAW_TRUE); + } else if (test(lex, TK_ENUM)) { + return enum_decl(lex, PAW_TRUE); } else if (test(lex, TK_STRUCT)) { return struct_decl(lex, PAW_TRUE); } else { @@ -1141,6 +1281,8 @@ static AstDecl *decl(Lex *lex) switch (lex->t.kind) { case TK_FN: return func_decl(lex, lex->line, PAW_FALSE); + case TK_ENUM: + return enum_decl(lex, PAW_FALSE); case TK_STRUCT: return struct_decl(lex, PAW_FALSE); case TK_TYPE: @@ -1185,6 +1327,7 @@ static AstStmt *statement(Lex *lex) case TK_CONTINUE: return label_stmt(lex, LCONTINUE); case TK_FN: + case TK_ENUM: case TK_STRUCT: case TK_LET: case TK_GLOBAL: @@ -1196,10 +1339,21 @@ static AstStmt *statement(Lex *lex) } static const char kPrelude[] = - "struct Vector[T] {}\n" - "struct Map[K, V] {}\n" + // Builtin structures: + "struct Vector[T] {} \n" + "struct Map[K, V] {} \n" + // Builtin enumerations: + "enum Option[T] { \n" + " Some(T), \n" + " None, \n" + "} \n" + "enum Result[T, E] { \n" + " Ok(T), \n" + " Err(E), \n" + "} \n" + // Builtin functions: "fn print(message: string) {}\n" - "fn assert(cond: bool) {}\n" + "fn assert(cond: bool) {} \n" // TODO: Using these until Paw has methods. "fn v_push[T](vec: Vector[T], elem: T) {}\n" "fn v_pop[T](vec: Vector[T]) -> T {}\n" @@ -1232,8 +1386,24 @@ static AstList *load_prelude(Lex *lex) // // ORDER TokenKind static const char *kKeywords[] = { - "fn", "type", "struct", "global", "let", "if", "else", "for", - "do", "while", "break", "continue", "return", "in", "true", "false", + "fn", + "type", + "enum", + "struct", + "global", + "match", + "let", + "if", + "else", + "for", + "do", + "while", + "break", + "continue", + "return", + "in", + "true", + "false", }; static String *basic_type_name(paw_Env *P, const char *name, paw_Type type) @@ -1336,10 +1506,7 @@ Closure *pawP_parse(paw_Env *P, paw_Reader input, ParseMemory *pm, // Compile the module. parse_module(&lex, input, ud); // pass 1 (source -> AST) p_check_types(&lex); // pass 2 (AST -> graph) - - // pawA_dump_stmt(stdout, lex.pm->ast->stmts->first); // TODO: remove - - p_generate_code(&lex); // pass 2 (graph -> bytecode) + p_generate_code(&lex); // pass 3 (graph -> bytecode) // Pop the lexer map. The strings it contains should be anchored elsewhere. // Leave the main closure on top of the stack. diff --git a/src/parse.h b/src/parse.h index 2991963..0873345 100644 --- a/src/parse.h +++ b/src/parse.h @@ -86,22 +86,20 @@ void pawP_add_scope(Lex *lex, SymbolTable *table, Scope *scope); struct Symbol *pawP_add_symbol(Lex *lex, Scope *table); int pawP_find_symbol(Scope *scope, const String *name); +struct MatchState { + struct MatchState *outer; + struct MatchExpr *match; + AstType *target; + AstType *value; +}; + typedef struct GenericState { struct GenericState *outer; } GenericState; -typedef struct StructState { - struct StructState *outer; - struct StructDecl *struct_; - struct AstDecl *method; - struct AstDecl *field; - int imethod; - int ifield; -} StructState; - typedef struct BlockState { struct BlockState *outer; - uint8_t is_loop; + paw_Bool is_loop: 1; int isymbol; int level; int label0; @@ -110,6 +108,7 @@ typedef struct BlockState { typedef struct LocalSlot { struct Symbol *symbol; int index; + paw_Bool is_captured: 1; } LocalSlot; typedef struct LocalStack { @@ -136,9 +135,7 @@ typedef struct FuncState { BlockState *bs; // current block Proto *proto; // prototype being built String *name; // name of the function - int id; // index in caller's prototype list int level; // current stack index (base = 0) - int ndebug; // number of debug entries int nup; // number of upvalues int nk; // number of constants int nproto; // number of nested functions @@ -166,11 +163,6 @@ typedef struct ParseMemory { int alloc; } scratch; - struct { - Binder data[MAX_BINDERS]; - int size; - } temp; - struct { FuncSig *data; int size; diff --git a/src/paw.h b/src/paw.h index d536fcb..96ba818 100644 --- a/src/paw.h +++ b/src/paw.h @@ -60,6 +60,7 @@ int paw_load(paw_Env *P, paw_Reader input, const char *name, void *ud); // the last parameter on top. int paw_call(paw_Env *P, int argc); +// Builtin types // ORDER ValueType #define PAW_TUNIT 0 #define PAW_TBOOL 1 @@ -70,8 +71,8 @@ int paw_call(paw_Env *P, int argc); #define PAW_TMAP 6 #define PAW_TTUPLE 7 #define PAW_TENUM 8 -#define PAW_TFUNCTION 9 -#define PAW_TSTRUCT 10 +#define PAW_TSTRUCT 9 +#define PAW_TFUNCTION 10 #define PAW_TFOREIGN 11 #define PAW_TMODULE 12 #define PAW_NTYPES 13 diff --git a/src/rt.c b/src/rt.c index f19fa7b..a6cf9cf 100644 --- a/src/rt.c +++ b/src/rt.c @@ -33,9 +33,9 @@ break; \ default #define vm_continue continue -#define vm_shift(n) (*vm_peek(n) = *vm_peek(0), vm_pop(n)) +#define vm_shift(n) (*vm_top((n) + 1) = *vm_top(1), vm_pop(n)) #define vm_pop(n) pawC_stkdec(P, n) -#define vm_peek(n) (&P->top.p[-(n) - 1]) +#define vm_top(n) (&P->top.p[-(n)]) #define vm_save() (vm_protect(), cf->top = P->top) #define vm_protect() (cf->pc = pc) #define vm_upvalue(o) (fn->up[get_U(o)]->p.p) @@ -64,6 +64,13 @@ pm = pawH_new(P); \ v_set_object(pv, pm); +static void add_zeros(paw_Env *P, int n) +{ + for (int i = 0; i < n; ++i) { + vm_push0(); + } +} + static int current_line(const CallFrame *cf) { Proto *p = cf->fn->p; @@ -173,45 +180,43 @@ static paw_Bool consume_prefix(const char **str) void pawR_cast_bool(paw_Env *P, paw_Type type) { paw_assert(type < PAW_TSTRING); - StackPtr sp = vm_peek(0); - if (type == PAW_TFLOAT) { - const paw_Float f = v_float(*sp); - v_set_bool(sp, f != 0.0); - } else if (type == PAW_TINT) { - const paw_Int i = v_int(*sp); - v_set_bool(sp, i != 0); - } + paw_unused(type); + + Value *pv = vm_top(1); + v_set_bool(pv, pv->u != 0); } void pawR_cast_int(paw_Env *P, paw_Type type) { paw_assert(type < PAW_TSTRING); - StackPtr sp = vm_peek(0); if (type == PAW_TFLOAT) { - const paw_Float f = v_float(*sp); - float2int(P, f, sp); + // NOTE: Other primitives have a value representation compatible with + // that of the 'int' type. + Value *pv = vm_top(1); + const paw_Float f = v_float(*pv); + float2int(P, f, pv); } } void pawR_cast_float(paw_Env *P, paw_Type type) { paw_assert(type < PAW_TSTRING); - StackPtr sp = vm_peek(0); if (type != PAW_TFLOAT) { - const paw_Int i = v_int(*sp); - v_set_float(sp, (paw_Float)i); + Value *pv = vm_top(1); + const paw_Int i = v_int(*pv); + v_set_float(pv, cast(i, paw_Float)); } } void pawR_to_bool(paw_Env *P, paw_Type type) { - Value *pv = vm_peek(0); + Value *pv = vm_top(1); v_set_bool(pv, pawV_truthy(*pv, type)); } void pawR_to_int(paw_Env *P, paw_Type type) { - StackPtr sp = vm_peek(0); + StackPtr sp = vm_top(1); if (type == PAW_TSTRING) { const char *begin = v_text(*sp); const char *str = begin; @@ -220,7 +225,7 @@ void pawR_to_int(paw_Env *P, paw_Type type) pawR_error(P, PAW_ESYNTAX, "invalid integer '%s'", str); } if (neg) { - sp = vm_peek(0); // new top + sp = vm_top(1); // new top const paw_Int i = v_int(*sp); if (i == PAW_INT_MIN) { pawR_error(P, PAW_EOVERFLOW, @@ -236,7 +241,7 @@ void pawR_to_int(paw_Env *P, paw_Type type) void pawR_to_float(paw_Env *P, paw_Type type) { - StackPtr sp = vm_peek(0); + StackPtr sp = vm_top(1); if (type == PAW_TSTRING) { const char *begin = v_text(*sp); const char *str = begin; @@ -245,7 +250,7 @@ void pawR_to_float(paw_Env *P, paw_Type type) pawR_error(P, PAW_ESYNTAX, "invalid float '%s'", begin); } if (neg) { - sp = vm_peek(0); // new top + sp = vm_top(1); // new top const paw_Float f = v_float(*sp); v_set_float(sp, -f); } @@ -257,25 +262,12 @@ void pawR_to_float(paw_Env *P, paw_Type type) const char *pawR_to_string(paw_Env *P, paw_Type type, size_t *plen) { - Value v = *vm_peek(0); + Value v = *vm_top(1); const char *out = pawV_to_string(P, v, type, plen); vm_shift(1); return out; } -// static Value *find_attr(paw_Env *P, Value obj, Value name) -//{ -// Map *attr = NULL; -// if (t_is_instance(obj)) { -// attr = v_instance(obj)->attr; -// } else if (t_is_foreign(obj)) { -// attr = v_foreign(obj)->attr; -// } else { -// return NULL; -// } -// return pawH_get(P, attr, name); -// } - void pawR_read_global(paw_Env *P, int g) { paw_assert(g < P->gv.size); @@ -286,7 +278,7 @@ void pawR_read_global(paw_Env *P, int g) void pawR_write_global(paw_Env *P, int g) { GlobalVar *global = &P->gv.data[g]; - global->value = *vm_peek(0); + global->value = *vm_top(1); vm_pop(1); } @@ -323,11 +315,18 @@ void pawR_close_upvalues(paw_Env *P, const StackPtr top) } } -void pawR_setattr(paw_Env *P, int index) +void pawR_settuple(paw_Env *P, int index) { - const Value val = *vm_peek(0); - const Value obj = *vm_peek(1); + const Value val = *vm_top(1); + const Value obj = *vm_top(2); + v_tuple(obj)->elems[index] = val; + vm_pop(2); +} +void pawR_setattr(paw_Env *P, int index) +{ + const Value val = *vm_top(1); + const Value obj = *vm_top(2); Instance *ins = v_instance(obj); ins->attrs[1 + index] = val; vm_pop(2); @@ -335,13 +334,13 @@ void pawR_setattr(paw_Env *P, int index) void pawR_setitem(paw_Env *P, paw_Type ttarget) { - const Value val = *vm_peek(0); - const Value key = *vm_peek(1); - const Value obj = *vm_peek(2); + const Value val = *vm_top(1); + const Value key = *vm_top(2); + const Value obj = *vm_top(3); if (ttarget == PAW_TVECTOR) { - const paw_Int idx = v_int(key); - Value *slot = pawA_get(P, v_vector(obj), idx); - *slot = val; + const paw_Int index = v_int(key); + Value *pval = pawA_get(P, v_vector(obj), index); + *pval = val; } else { paw_assert(ttarget == PAW_TMAP); pawH_insert(P, v_map(obj), key, val); @@ -361,17 +360,17 @@ void pawR_init(paw_Env *P) static paw_Bool fornum_init(paw_Env *P) { - const paw_Int begin = v_int(*vm_peek(2)); - const paw_Int end = v_int(*vm_peek(1)); - const paw_Int step = v_int(*vm_peek(0)); + const paw_Int begin = v_int(*vm_top(3)); + const paw_Int end = v_int(*vm_top(2)); + const paw_Int step = v_int(*vm_top(1)); if (step == 0) { pawR_error(P, PAW_ERUNTIME, "loop step equals 0"); } const paw_Bool skip = stop_loop(begin, end, step); if (!skip) { - v_set_int(vm_peek(2), begin); - v_set_int(vm_peek(1), end); - v_set_int(vm_peek(0), step); + v_set_int(vm_top(3), begin); + v_set_int(vm_top(2), end); + v_set_int(vm_top(1), step); vm_pushi(begin); } return skip; @@ -379,21 +378,21 @@ static paw_Bool fornum_init(paw_Env *P) static paw_Bool fornum(paw_Env *P) { - const paw_Int itr = v_int(*vm_peek(2)); - const paw_Int step = v_int(*vm_peek(0)); - const paw_Int end = v_int(*vm_peek(1)); + const paw_Int itr = v_int(*vm_top(3)); + const paw_Int step = v_int(*vm_top(1)); + const paw_Int end = v_int(*vm_top(2)); const paw_Int next = itr + step; if (stop_loop(next, end, step)) { return PAW_FALSE; } - v_set_int(vm_peek(2), next); + v_set_int(vm_top(3), next); vm_pushi(next); return PAW_TRUE; } static paw_Bool forin_init(paw_Env *P, paw_Type t) { - // const Value v = *vm_peek(0); + // const Value v = *vm_top(1); // paw_Int itr = PAW_ITER_INIT; // if (t == PAW_TVECTOR) { // Vector *arr = v_vector(v); @@ -411,18 +410,18 @@ static paw_Bool forin_init(paw_Env *P, paw_Type t) //// return PAW_FALSE; //// } // } - // return PAW_TRUE; + return PAW_TRUE; } static paw_Bool forin(paw_Env *P, paw_Type t) { - // const Value obj = *vm_peek(1); - // const Value itr = *vm_peek(0); + // const Value obj = *vm_top(2); + // const Value itr = *vm_top(1); // if (t == PAW_TVECTOR) { // Vector *arr = v_vector(obj); // paw_Int i = v_int(itr); // if (pawA_iter(arr, &i)) { - // v_set_int(vm_peek(0), i); + // v_set_int(vm_top(1), i); // vm_pushv(arr->begin[i]); // return PAW_TRUE; // } @@ -431,12 +430,12 @@ static paw_Bool forin(paw_Env *P, paw_Type t) //// Map *map = v_map(obj); //// paw_Int i = v_int(itr); //// if (pawH_iter(map, &i)) { - //// v_set_int(vm_peek(0), i); + //// v_set_int(vm_top(1), i); //// vm_pushv(map->keys[i]); //// return PAW_TRUE; //// } // } - // return PAW_FALSE; // stop the loop + return PAW_FALSE; // stop the loop } #define finish_strcmp(x, y, op) (pawS_cmp(x, y) op 0) @@ -488,7 +487,7 @@ static void eq_ne(paw_Env *P, BinaryOp binop, paw_Type t, Value x, Value y) // Fall back to comparing the value representation. result = x.u == y.u; } - v_set_bool(vm_peek(1), result ? bt : bf); + v_set_bool(vm_top(2), result ? bt : bf); vm_pop(1); } @@ -570,15 +569,15 @@ static void int_binop(paw_Env *P, BinaryOp binop, paw_Int x, paw_Int y) z = x >> y; } } - v_set_int(vm_peek(1), z); + v_set_int(vm_top(2), z); vm_pop(1); } -#define finish_cmp(x, y, op) (v_set_bool(vm_peek(1), (x)op(y)), vm_pop(1)) +#define finish_cmp(x, y, op) (v_set_bool(vm_top(2), (x)op(y)), vm_pop(1)) static void float_binop(paw_Env *P, BinaryOp binop, paw_Float x, paw_Float y) { - Value *pv = vm_peek(1); + Value *pv = vm_top(2); switch (binop) { case BINARY_LT: finish_cmp(x, y, <); @@ -619,10 +618,10 @@ static void other_binop(paw_Env *P, BinaryOp binop, paw_Type t, Value x, { if (binop == BINARY_IN) { if (t == PAW_TVECTOR) { - v_set_bool(vm_peek(1), pawA_contains(P, v_vector(y), x)); + v_set_bool(vm_top(2), pawA_contains(P, v_vector(y), x)); } else { paw_assert(t == PAW_TMAP); - v_set_bool(vm_peek(1), pawH_contains(P, v_map(y), x)); + v_set_bool(vm_top(2), pawH_contains(P, v_map(y), x)); } vm_pop(1); } else { @@ -647,14 +646,14 @@ static int binop_aux(paw_Env *P, BinaryOp binop, paw_Type t, Value x, Value y) void pawR_binop(paw_Env *P, BinaryOp binop, paw_Type t) { - const Value x = *vm_peek(1); - const Value y = *vm_peek(0); + const Value x = *vm_top(2); + const Value y = *vm_top(1); binop_aux(P, binop, t, x, y); } static void int_unop(paw_Env *P, UnaryOp unop, paw_Int i) { - Value *pv = vm_peek(0); + Value *pv = vm_top(1); switch (unop) { case UNARY_NEG: v_set_int(pv, i_unop(i, -)); @@ -670,7 +669,7 @@ static void int_unop(paw_Env *P, UnaryOp unop, paw_Int i) static void float_unop(paw_Env *P, UnaryOp unop, paw_Float f) { - Value *pv = vm_peek(0); + Value *pv = vm_top(1); switch (unop) { case UNARY_NEG: v_set_float(pv, -f); @@ -685,11 +684,11 @@ static void other_unop(paw_Env *P, UnaryOp unop, paw_Type t, Value x) { if (unop == UNARY_LEN) { // Replace the container with its length. - v_set_int(vm_peek(0), pawV_length(x, t)); + v_set_int(vm_top(1), pawV_length(x, t)); } else { paw_assert(unop == UNARY_NOT); // allows expressions like '!str' - v_set_bool(vm_peek(0), !pawV_truthy(x, t)); + v_set_bool(vm_top(1), !pawV_truthy(x, t)); } } @@ -706,63 +705,77 @@ static void unop_aux(paw_Env *P, UnaryOp unop, paw_Type t, Value x) void pawR_unop(paw_Env *P, UnaryOp unop, paw_Type t) { - const Value x = *vm_peek(0); + const Value x = *vm_top(1); unop_aux(P, unop, t, x); } -void pawR_getattr(paw_Env *P, int index) +void pawR_gettuple(paw_Env *P, int index) { - const Value obj = *vm_peek(0); + Tuple *tup = v_tuple(*vm_top(1)); + *vm_top(1) = tup->elems[index]; +} - Instance *ins = v_instance(obj); - *vm_peek(0) = ins->attrs[1 + index]; +void pawR_getattr(paw_Env *P, int index) +{ + Instance *ins = v_instance(*vm_top(1)); + *vm_top(1) = ins->attrs[1 + index]; } -static void getitem_vector(paw_Env *P, Value obj, Value key) +static void getitem_vector(paw_Env *P, Vector *vector, paw_Int index) { - Vector *vec = v_vector(obj); - *vm_peek(1) = *pawA_get(P, vec, v_int(key)); + *vm_top(2) = *pawA_get(P, vector, index); vm_pop(1); } -static int getitem_map(paw_Env *P, Value obj, Value key) +static int getitem_map(paw_Env *P, Map *map, Value key) { - const Value *pv = pawH_get(P, v_map(obj), key); + const Value *pv = pawH_get(P, map, key); if (pv) { - *vm_peek(1) = *pv; + *vm_top(2) = *pv; vm_pop(1); return 0; } return -1; } -static void getitem_string(paw_Env *P, Value obj, Value key) +static void getitem_string(paw_Env *P, const String *string, paw_Int index) { - paw_Int idx = v_int(key); - String *str = v_string(obj); - pawA_check_abs(P, idx, str->length); - const char c = str->text[idx]; + pawA_check_abs(P, index, string->length); + const char c = string->text[index]; String *res = pawS_new_nstr(P, &c, 1); - v_set_object(vm_peek(1), res); + v_set_object(vm_top(2), res); vm_pop(1); } int pawR_getitem(paw_Env *P, paw_Type ttarget) { - const Value obj = *vm_peek(1); - const Value key = *vm_peek(0); + const Value obj = *vm_top(2); + const Value key = *vm_top(1); + if (ttarget == PAW_TMAP) { + return getitem_map(P, v_map(obj), key); + } if (ttarget == PAW_TVECTOR) { - getitem_vector(P, obj, key); - } else if (ttarget == PAW_TMAP) { - if (getitem_map(P, obj, key)) { - return -1; - } + getitem_vector(P, v_vector(obj), v_int(key)); } else if (ttarget == PAW_TSTRING) { - getitem_string(P, obj, key); + getitem_string(P, v_string(obj), v_int(key)); } return 0; } +void pawR_literal_tuple(paw_Env *P, int n) +{ + Value *pv = vm_push0(); + Tuple *tuple = pawV_new_tuple(P, n); + v_set_object(pv, tuple); + + Value *dst = tuple->elems + n; + const Value *src = vm_top(1); + for (int i = 0; i < n; ++i) { + *--dst = *--src; + } + vm_shift(n); +} + void pawR_literal_vector(paw_Env *P, int n) { Vector *v; @@ -794,24 +807,42 @@ void pawR_literal_map(paw_Env *P, int n) } } -// TODO: 'null' -> Option[T]::None -// static paw_Bool should_jump_null(paw_Env *P) -//{ -// const Value *pv = vm_peek(0); -//// if (meta_single(P, MM_NULL, *pv)) { -//// if (v_is_null(*vm_peek(0))) { -//// vm_pop(1); -//// return PAW_TRUE; -//// } -//// vm_shift(1); -//// return PAW_FALSE; -//// } -// return v_is_null(*pv); -//} - -static paw_Bool should_jump_false(paw_Env *P) -{ - return !v_true(*vm_peek(0)); +static void new_variant(paw_Env *P, int k, int nfields) +{ + Value *pv = vm_push0(); + Variant *var = pawV_new_variant(P, k, nfields); + v_set_object(pv, var); + for (int i = 0; i < nfields; ++i) { + var->fields[i] = P->top.p[i - nfields - 1]; + } + vm_shift(nfields); +} + +static void unpack_variant(paw_Env *P, int n) +{ + const Variant *v = v_variant(*vm_top(1)); + add_zeros(P, n - 1); + for (int i = 0; i < n; ++i) { + *vm_top(n - i + 1) = v->fields[i]; + } +} + +static void unpack_instance(paw_Env *P, int n) +{ + const Instance *s = v_instance(*vm_top(1)); + add_zeros(P, n - 1); + for (int i = 0; i < n; ++i) { + *vm_top(n - i + 1) = s->attrs[i]; + } +} + +static void unpack_tuple(paw_Env *P, int n) +{ + const Tuple *t = v_tuple(*vm_top(1)); + add_zeros(P, n - 1); + for (int i = 0; i < n; ++i) { + *vm_top(n - i + 1) = t->elems[i]; + } } void pawR_execute(paw_Env *P, CallFrame *cf) @@ -834,7 +865,19 @@ void pawR_execute(paw_Env *P, CallFrame *cf) { vm_case(POP) : { - vm_pop(1); + vm_pop(get_U(opcode)); + } + + vm_case(CLOSE) : + { + const int u = get_U(opcode); + pawR_close_upvalues(P, vm_top(u)); + vm_pop(u); + } + + vm_case(COPY) : + { + vm_pushv(*vm_top(1)); } vm_case(PUSHUNIT) : @@ -874,6 +917,13 @@ void pawR_execute(paw_Env *P, CallFrame *cf) pawR_binop(P, get_A(opcode), get_B(opcode)); } + vm_case(NEWTUPLE) : + { + vm_protect(); + pawR_literal_tuple(P, get_U(opcode)); + check_gc(P); + } + vm_case(NEWVECTOR) : { vm_protect(); @@ -903,12 +953,43 @@ void pawR_execute(paw_Env *P, CallFrame *cf) pawR_cast_float(P, get_U(opcode)); } + vm_case(MATCHVARIANT) : + { + const Variant *var = v_variant(*vm_top(1)); + vm_pushb(var->k == get_U(opcode)); + } + + vm_case(UNPACKVARIANT) : + { + vm_protect(); + unpack_variant(P, get_U(opcode)); + } + + vm_case(UNPACKINSTANCE) : + { + vm_protect(); + unpack_instance(P, get_U(opcode)); + } + + vm_case(UNPACKTUPLE) : + { + vm_protect(); + unpack_tuple(P, get_U(opcode)); + } + + vm_case(NEWVARIANT) : + { + vm_protect(); + new_variant(P, get_A(opcode), get_B(opcode)); + check_gc(P); + } + // TODO: Instances store a pointer to Struct as the first field. This was how // method calls were implemented before the switch to static typing. vm_case(NEWINSTANCE) : { vm_protect(); - Value *pv = vm_peek(0); + Value *pv = vm_top(1); Struct *struct_ = v_struct(*pv); Instance *ins = pawV_new_instance(P, 1 + get_U(opcode)); v_set_object(ins->attrs, struct_); @@ -920,8 +1001,8 @@ void pawR_execute(paw_Env *P, CallFrame *cf) { vm_protect(); const int u = get_U(opcode); - Instance *ins = v_instance(*vm_peek(1)); - ins->attrs[1 + u] = *vm_peek(0); + Instance *ins = v_instance(*vm_top(2)); + ins->attrs[1 + u] = *vm_top(1); vm_pop(1); } @@ -934,7 +1015,7 @@ void pawR_execute(paw_Env *P, CallFrame *cf) vm_case(SETLOCAL) : { Value *plocal = &cf->base.p[get_U(opcode)]; - *plocal = *vm_peek(0); + *plocal = *vm_top(1); vm_pop(1); } @@ -947,7 +1028,7 @@ void pawR_execute(paw_Env *P, CallFrame *cf) vm_case(SETUPVALUE) : { Value *pupval = vm_upvalue(opcode); - *pupval = *vm_peek(0); + *pupval = *vm_top(1); vm_pop(1); } @@ -963,25 +1044,35 @@ void pawR_execute(paw_Env *P, CallFrame *cf) pawR_write_global(P, u); } + vm_case(GETTUPLE) : + { + vm_protect(); + pawR_gettuple(P, get_U(opcode)); + } + vm_case(GETATTR) : { vm_protect(); - const int u = get_U(opcode); - pawR_getattr(P, u); + pawR_getattr(P, get_U(opcode)); + } + + vm_case(SETTUPLE) : + { + vm_protect(); + pawR_settuple(P, get_U(opcode)); } vm_case(SETATTR) : { vm_protect(); - const int u = get_U(opcode); - pawR_setattr(P, u); + pawR_setattr(P, get_U(opcode)); } vm_case(GETITEM) : { vm_protect(); if (pawR_getitem(P, get_A(opcode))) { - pawH_key_error(P, *vm_peek(0), PAW_TSTRING); // TODO: lookup key type + pawH_key_error(P, *vm_top(1), PAW_TSTRING); // TODO: lookup key type } } @@ -991,12 +1082,6 @@ void pawR_execute(paw_Env *P, CallFrame *cf) pawR_setitem(P, get_U(opcode)); } - vm_case(CLOSE) : - { - pawR_close_upvalues(P, vm_peek(1)); - vm_pop(1); - } - vm_case(CLOSURE) : { vm_protect(); @@ -1020,7 +1105,7 @@ void pawR_execute(paw_Env *P, CallFrame *cf) vm_case(CALL) : { const uint8_t argc = get_U(opcode); - StackPtr ptr = vm_peek(argc); + StackPtr ptr = vm_top(argc + 1); vm_save(); CallFrame *callee = pawC_precall(P, ptr, v_object(*ptr), argc); @@ -1030,15 +1115,25 @@ void pawR_execute(paw_Env *P, CallFrame *cf) } } + vm_case(TRANSIT) : + { + const int u = get_U(opcode); + const Value v = *vm_top(1); + vm_pop(u - 1); + + pawR_close_upvalues(P, vm_top(1)); + *vm_top(1) = v; + } + vm_case(RETURN) : { - const Value result = *vm_peek(0); + const Value result = *vm_top(1); vm_pop(1); P->top.p = cf_stack_return(cf); vm_save(); - pawR_close_upvalues(P, vm_peek(0)); + pawR_close_upvalues(P, vm_top(1)); vm_pushv(result); P->cf = cf->prev; if (cf_is_entry(cf)) { @@ -1053,23 +1148,24 @@ void pawR_execute(paw_Env *P, CallFrame *cf) pc += get_S(opcode); } - // vm_case(JUMPNULL) : - // { - // if (should_jump_null(P)) { - // pc += get_S(opcode); - // } - // } + vm_case(JUMPNULL) : + { + const Variant *pv = v_variant(*vm_top(1)); + if (pv->k == 0) { + pc += get_S(opcode); + } + } vm_case(JUMPFALSE) : { - if (should_jump_false(P)) { + if (!v_true(*vm_top(1))) { pc += get_S(opcode); } } vm_case(JUMPFALSEPOP) : { - if (should_jump_false(P)) { + if (!v_true(*vm_top(1))) { pc += get_S(opcode); } vm_pop(1); diff --git a/src/rt.h b/src/rt.h index 8de9ae7..f47e4a3 100644 --- a/src/rt.h +++ b/src/rt.h @@ -22,8 +22,10 @@ void pawR_attr_error(paw_Env *P, Value attr); void pawR_name_error(paw_Env *P, Value name); void pawR_getattr(paw_Env *P, int index); +void pawR_gettuple(paw_Env *P, int index); int pawR_getitem(paw_Env *P, paw_Type ttarget); void pawR_setattr(paw_Env *P, int index); +void pawR_settuple(paw_Env *P, int index); void pawR_setitem(paw_Env *P, paw_Type ttarget); int pawR_getattr_raw(paw_Env *P, paw_Bool fallback); diff --git a/src/unify.c b/src/unify.c index 8d595ac..c505f01 100644 --- a/src/unify.c +++ b/src/unify.c @@ -40,24 +40,15 @@ typedef struct UniTable { static void dump_type(FILE *out, const AstType *type) { switch (a_kind(type)) { - case AST_TYPE_BASIC: - switch (type->hdr.def) { - case PAW_TUNIT: - fprintf(out, "()"); - break; - case PAW_TBOOL: - fprintf(out, "bool"); - break; - case PAW_TINT: - fprintf(out, "int"); - break; - case PAW_TFLOAT: - fprintf(out, "float"); - break; - default: - paw_assert(type->hdr.def == PAW_TSTRING); - fprintf(out, "string"); + case AST_TYPE_TUPLE: + fprintf(out, "("); + for (int i = 0; i < type->tuple.elems->count; ++i) { + dump_type(out, type->tuple.elems->data[i]); + if (i < type->tuple.elems->count - 1) { + fprintf(out, ", "); + } } + fprintf(out, ")"); break; case AST_TYPE_FUNC: fprintf(out, "fn("); @@ -68,7 +59,7 @@ static void dump_type(FILE *out, const AstType *type) } } fprintf(out, ") -> "); - dump_type(out, type->func.return_); + dump_type(out, type->func.result); break; case AST_TYPE_ADT: fprintf(out, "%d", type->adt.base); // TODO: Print the name @@ -85,7 +76,7 @@ static void dump_type(FILE *out, const AstType *type) } break; case AST_TYPE_UNKNOWN: - fprintf(out, "?%d", type->unknown.def); + fprintf(out, ""); break; default: paw_assert(a_is_generic(type)); @@ -162,19 +153,23 @@ static void unify_binders(Unifier *U, AstList *a, AstList *b) } } -static void unify_adt(Unifier *U, AstAdt *a, AstType *b) +static void unify_adt(Unifier *U, AstAdt *a, AstAdt *b) { - if (a->base != b->adt.base) { + if (a->base != b->base) { pawX_error(U->lex, "data types are incompatible"); } - unify_binders(U, a->types, b->adt.types); + unify_binders(U, a->types, b->types); +} + +static void unify_tuple(Unifier *U, AstTupleType *a, AstTupleType *b) +{ + unify_binders(U, a->elems, b->elems); } -static void unify_func_sig(Unifier *U, AstFuncSig *a, AstType *b) +static void unify_func(Unifier *U, AstFuncPtr *a, AstFuncPtr *b) { - // NOTE: 'types' field not unified (not part of function signature) - unify_binders(U, a->params, b->func.params); - pawU_unify(U, a->return_, b->func.return_); + unify_binders(U, a->params, b->params); + pawU_unify(U, a->result, b->result); } static AstType *unify_basic(Unifier *U, AstType *a, AstType *b) @@ -189,12 +184,15 @@ static AstType *unify_basic(Unifier *U, AstType *a, AstType *b) static void unify_types(Unifier *U, AstType *a, AstType *b) { debug_log("unify_types", a, b); - if (a_kind(a) != a_kind(b)) { + if ((a_is_fptr(a) || a_is_func(a)) && + (a_is_fptr(b) || a_is_func(b))) { + unify_func(U, &a->fptr, &b->fptr); + } else if (a_kind(a) != a_kind(b)) { pawX_error(U->lex, "incompatible types"); - } else if (a_is_func(a)) { - unify_func_sig(U, &a->func, b); + } else if (a_is_tuple(a)) { + unify_tuple(U, &a->tuple, &b->tuple); } else if (a_is_adt(a)) { - unify_adt(U, &a->adt, b); + unify_adt(U, &a->adt, &b->adt); } else { unify_basic(U, a, b); } @@ -228,7 +226,7 @@ void pawU_unify(Unifier *U, AstType *a, AstType *b) } } -AstType *pawU_new_unknown(Unifier *U, DefId id) +AstType *pawU_new_unknown(Unifier *U) { paw_Env *P = env(U->lex); Ast *ast = U->lex->pm->ast; @@ -242,7 +240,6 @@ AstType *pawU_new_unknown(Unifier *U, DefId id) AstType *type = pawA_new_type(ast, AST_TYPE_UNKNOWN); type->unknown.index = index; - type->unknown.def = id; // set contains only 'type' uvar->parent = uvar; diff --git a/src/unify.h b/src/unify.h index e658e44..c1315e9 100644 --- a/src/unify.h +++ b/src/unify.h @@ -23,7 +23,7 @@ AstType *pawU_normalize(UniTable *table, AstType *a); void pawU_unify(Unifier *U, AstType *a, AstType *b); // Create a new type variable -AstType *pawU_new_unknown(Unifier *U, DefId id); +AstType *pawU_new_unknown(Unifier *U); // Generics context handling void pawU_enter_binder(Unifier *U, UniTable *table); diff --git a/src/value.c b/src/value.c index e08cfa2..f47b365 100644 --- a/src/value.c +++ b/src/value.c @@ -149,7 +149,6 @@ void pawV_free_proto(paw_Env *P, Proto *f) pawM_free_vec(P, f->lines, f->nlines); pawM_free_vec(P, f->p, f->nproto); pawM_free_vec(P, f->k, f->nk); - pawM_free_vec(P, f->v, f->ndebug); pawM_free_vec(P, f->u, f->nup); pawM_free(P, f); } @@ -197,9 +196,10 @@ void pawV_unlink_upvalue(UpValue *u) Tuple *pawV_new_tuple(paw_Env *P, int nelems) { - Tuple *t = pawM_new_flex(P, Tuple, cast_size(nelems), sizeof(t->elems[0])); - pawG_add_object(P, cast_object(t), 0 /* TODO: VTUPLE*/); - return t; + Tuple *tuple = pawM_new_flex(P, Tuple, cast_size(nelems), + sizeof(tuple->elems[0])); + pawG_add_object(P, cast_object(tuple), VTUPLE); + return tuple; } void pawV_free_tuple(paw_Env *P, Tuple *t, int nelems) @@ -234,8 +234,7 @@ void pawV_free_struct(paw_Env *P, Struct *struct_) { pawM_free(P, struct_); } Instance *pawV_new_instance(paw_Env *P, int nfields) { - Instance *ins = - pawM_new_flex(P, Instance, cast_size(nfields), sizeof(ins->attrs[0])); + Instance *ins = pawM_new_flex(P, Instance, cast_size(nfields), sizeof(ins->attrs[0])); pawG_add_object(P, cast_object(ins), VINSTANCE); return ins; } @@ -245,6 +244,31 @@ void pawV_free_instance(paw_Env *P, Instance *ins, int nfields) pawM_free_flex(P, ins, cast_size(nfields), sizeof(ins->attrs[0])); } +Enum *pawV_new_enum(paw_Env *P, int nvariants) +{ + Enum *e = pawM_new_flex(P, Enum, cast_size(nvariants), sizeof(e->variants[0])); + pawG_add_object(P, cast_object(e), VENUM); + return e; +} + +void pawV_free_enum(paw_Env *P, Enum *e, int nvariants) +{ + pawM_free_flex(P, e, cast_size(nvariants), sizeof(e->variants[0])); +} + +Variant *pawV_new_variant(paw_Env *P, int k, int nfields) +{ + Variant *var = pawM_new_flex(P, Variant, cast_size(nfields), sizeof(var->fields[0])); + pawG_add_object(P, cast_object(var), VVARIANT); + var->k = k; + return var; +} + +void pawV_free_variant(paw_Env *P, Variant *var, int nfields) +{ + pawM_free_flex(P, var, cast_size(nfields), sizeof(var->fields[0])); +} + Value *pawV_find_attr(Value *attrs, String *name, Type *type) { // const CompositeType *cls = &type->cls; diff --git a/src/value.h b/src/value.h index cf75ad0..7251fc5 100644 --- a/src/value.h +++ b/src/value.h @@ -26,6 +26,9 @@ #define v_map(v) (o_map(v_object(v))) #define v_vector(v) (o_vector(v_object(v))) #define v_text(v) (v_string(v)->text) +#define v_tuple(v) (o_tuple(v_object(v))) +#define v_variant(v) (o_variant(v_object(v))) +#define v_enum(v) (o_enum(v_object(v))) #define v_instance(v) (o_instance(v_object(v))) #define v_struct(v) (o_struct(v_object(v))) #define v_method(v) (o_method(v_object(v))) @@ -45,6 +48,9 @@ #define o_is_upvalue(o) (o_kind(o) == VUPVALUE) #define o_is_map(o) (o_kind(o) == VMAP) #define o_is_vector(o) (o_kind(o) == VVECTOR) +#define o_is_tuple(o) (o_kind(o) == VTUPLE) +#define o_is_variant(o) (o_kind(o) == VVARIANT) +#define o_is_enum(o) (o_kind(o) == VENUM) #define o_is_instance(o) (o_kind(o) == VINSTANCE) #define o_is_struct(o) (o_kind(o) == VSTRUCT) #define o_is_method(o) (o_kind(o) == VMETHOD) @@ -57,37 +63,17 @@ #define o_upvalue(o) check_exp(o_is_upvalue(o), (UpValue *)(o)) #define o_map(o) check_exp(o_is_map(o), (Map *)(o)) #define o_vector(o) check_exp(o_is_vector(o), (Vector *)(o)) +#define o_tuple(o) check_exp(o_is_tuple(o), (Tuple *)(o)) +#define o_variant(o) check_exp(o_is_variant(o), (Variant *)(o)) +#define o_enum(o) check_exp(o_is_enum(o), (Enum *)(o)) #define o_instance(o) check_exp(o_is_instance(o), (Instance *)(o)) #define o_struct(o) check_exp(o_is_struct(o), (Struct *)(o)) #define o_method(o) check_exp(o_is_method(o), (Method *)(o)) #define o_foreign(o) check_exp(o_is_foreign(o), (Foreign *)(o)) -#define GC_HEADER \ - struct Object *gc_next; \ - uint64_t gc_nrefs; \ - uint8_t gc_kind #define cast_uintptr(x) ((uintptr_t)(x)) #define cast_object(x) ((Object *)(void *)(x)) -typedef struct Object { - GC_HEADER; -} Object; - -typedef union Value { - uint64_t u; - paw_Int i; - paw_Float f; - Object *o; - void *p; -} Value; - -typedef Value *StackPtr; - -typedef union StackRel { - ptrdiff_t d; - StackPtr p; -} StackRel; - typedef enum ValueKind { // scalar types VBOOL, @@ -99,7 +85,10 @@ typedef enum ValueKind { VVECTOR, VMAP, VSTRUCT, + VENUM, + VTUPLE, VINSTANCE, + VVARIANT, VMETHOD, VFOREIGN, VTYPE, @@ -115,6 +104,29 @@ typedef enum ValueKind { NVTYPES } ValueKind; +#define GC_HEADER \ + struct Object *gc_next; \ + uint64_t gc_nrefs; \ + ValueKind gc_kind: 8 +typedef struct Object { + GC_HEADER; +} Object; + +typedef union Value { + uint64_t u; + paw_Int i; + paw_Float f; + Object *o; + void *p; +} Value; + +typedef Value *StackPtr; + +typedef union StackRel { + ptrdiff_t d; + StackPtr p; +} StackRel; + static inline int pawV_type(ValueKind vt) { switch (vt) { @@ -176,11 +188,6 @@ typedef struct String { const char *pawV_to_string(paw_Env *P, Value v, paw_Type type, size_t *nout); paw_Int pawV_to_int(paw_Env *P, Value v, paw_Type type); -typedef struct VarDesc { - String *name; - paw_Type code; -} VarDesc; - typedef struct Proto { GC_HEADER; uint8_t is_va; @@ -190,15 +197,7 @@ typedef struct Proto { uint32_t *source; int length; - struct LocalInfo { - VarDesc var; - int pc0; - int pc1; - paw_Bool captured; - } *v; - struct UpValueInfo { - VarDesc var; uint16_t index; paw_Bool is_local; } *u; @@ -268,7 +267,7 @@ typedef struct Tuple { Tuple *pawV_new_tuple(paw_Env *P, int nelems); -typedef struct Vector { // TODO: Call this Vec +typedef struct Vector { GC_HEADER; Value *begin; Value *end; @@ -309,7 +308,6 @@ typedef struct Map { typedef struct Struct { GC_HEADER; // common members for GC paw_Type type; // index in module type list - VarDesc *fields; // RTTI for fields } Struct; Struct *pawV_new_struct(paw_Env *P, Value *pv); @@ -325,6 +323,23 @@ typedef struct Instance { Instance *pawV_new_instance(paw_Env *P, int nfields); void pawV_free_instance(paw_Env *P, Instance *ins, int nfields); +typedef struct Enum { + GC_HEADER; // common members for GC + Value variants[]; // enumerators +} Enum; + +Enum *pawV_new_enum(paw_Env *P, int nvariants); +void pawV_free_enum(paw_Env *P, Enum *e, int nvariants); + +typedef struct Variant { + GC_HEADER; // common members for GC + uint8_t k; // discriminator + Value fields[]; // data fields +} Variant; + +Variant *pawV_new_variant(paw_Env *P, int k, int nfields); +void pawV_free_variant(paw_Env *P, Variant *var, int nfields); + // Method bound to an instance typedef struct Method { GC_HEADER; diff --git a/test/.test_rt.c.swo b/test/.test_rt.c.swo deleted file mode 100644 index a937a4e..0000000 Binary files a/test/.test_rt.c.swo and /dev/null differ diff --git a/test/scripts/basic.paw b/test/scripts/basic.paw index 00d5cb9..0aff711 100644 --- a/test/scripts/basic.paw +++ b/test/scripts/basic.paw @@ -78,46 +78,6 @@ fn f(x: int, y: int, z: int) -> int {return z} assert(f(0, 1, 2) == 2) } -// -//// __*attr, and __*item -//{ -// class C {f() {return 42}} -// fn get() {return fn() {return C()}} -// let c = C() -// c.ins = C() -// c.ins.get = get -// c.ins.a = [0] -// let a = [c] -// // a = [ -// // C { <--------------------------------------- a[0] -// // f() {return 42}, <---------------------- a[0].f -// // ins = C { <----------------------------- a[0].ins -// // f() {return 42}, <------------------ a[0].ins.f -// // get = fn() { <---------------------- a[0].ins.get -// // return fn() { <----------------- a[0].ins.get() -// // return C { <---------------- a[0].ins.get()() -// // f = fn() {return 42} <-- a[0].ins.get()().f -// // } -// // } -// // } -// // } -// // } -// // ] -// // -// -// // __set* -// a[0].x = 1 -// a[0].ins.x = 2 -// a[0].ins.a[0] = 3 -// -// // __get* -// assert(a[0].f() == 42) -// assert(a[0].ins.f() == 42) -// assert(a[0].ins.get()().f() == 42) -// assert(a[0].x == 1) -// assert(a[0].ins.x == 2) -// assert(a[0].ins.a[0] == 3) -//} { fn f() -> int { @@ -125,7 +85,7 @@ // Return statement must be the last statement in the block. return 42 } - return 24 // Unreachable + return 24 // unreachable } assert(f() == 42) } @@ -142,59 +102,192 @@ } -//// Array and map are both 'prefixexpr' constructs, meaning they can appear to the -//// left of '[]' (__*item) or '.' (__*attr). See grammer.md for details. +// Short-circuiting behavior: +{ + let counts = (0, 0, 0) + fn check2(a: int, b: int) { + assert(counts.0 == a) + assert(counts.1 == b) + counts.0 = 0 + counts.1 = 0 + } + fn A(value: int) -> bool { + counts.0 = counts.0 + 1 + return bool(value) + } + fn B(value: int) -> bool { + counts.1 = counts.1 + 1 + return bool(value) + } + fn C(value: int) -> bool { + counts.2 = counts.2 + 1 + return bool(value) + } + + fn or(a: int, b: int) -> bool { + return A(a) || B(b) + } + assert(!or(0, 0)) + check2(1, 1) + assert(or(0, 1)) + check2(1, 1) + assert(or(1, 0)) + check2(1, 0) + assert(or(1, 1)) + check2(1, 0) + + fn and(a: int, b: int) -> bool { + return A(a) && B(b) + } + assert(!and(0, 0)) + check2(1, 0) + assert(!and(0, 1)) + check2(1, 0) + assert(!and(1, 0)) + check2(1, 1) + assert(and(1, 1)) + check2(1, 1) + + fn check3(a: int, b: int, c: int) { + check2(a, b) + assert(counts.2 == c) + counts.2 = 0 + } + + fn and_or(a: int, b: int, c: int) -> bool { + return A(a) && B(b) || C(c) + } + assert(!and_or(0, 0, 0)) + check3(1, 0, 1) + assert(!and_or(1, 0, 0)) + check3(1, 1, 1) + assert(!and_or(0, 1, 0)) + check3(1, 0, 1) + assert(and_or(0, 0, 1)) + check3(1, 0, 1) + assert(and_or(1, 1, 0)) + check3(1, 1, 0) + assert(and_or(0, 1, 1)) + check3(1, 0, 1) + assert(and_or(1, 0, 1)) + check3(1, 1, 1) + assert(and_or(1, 1, 1)) + check3(1, 1, 0) +} + +{ + struct C { + val: int + get: fn() -> fn() -> C + } + fn get() -> fn() -> C { + fn inner() -> C {return C{get: get, val: 123}} + return inner + } + let c = C{get: get, val: 0} + let v = Vector[C]{c} + + v[0].val = 42 + v[0].get()().val = 0 + assert(v[0].val == 42) + assert(v[0].get()().val == 123) +} + //{ -// let a = [0, 1, 2][1] -// assert(a == 1) +// let v = [0, 1, 2][1] +// assert(v == 1) // let m = {0: 0, 1: 1, 2: 2}[1] // assert(m == 1) //} { let s = '' - for a = 0, 10 { + for a = 0, 1 { s = s + 'a' - for b = 0, 10 { - s = s + 'b' - for c = 0, 10 { - s = s + 'c' + for b = 0, 2 { + s = 'b' + s + for c = 0, 3 { + s = 'c' + s + 'd' } } } + assert(s == 'cccbcccbadddddd') } -// TODO: Consider short-circuiting behavior -//{ -// fn test(a, b) { -// return a || b -// } -// assert(1 == test(0, 1)) -// assert(2 == test(2, 3)) -// -// fn test(a, b) { -// return a && b -// } -// assert(0 == test(0, 1)) -// assert(3 == test(2, 3)) -// -// fn test(a, b, c) { -// return a && b && c -// } -// assert(0 == test(0, 0, 0)) -// assert(0 == test(1, 0, 0)) -// assert(0 == test(1, 2, 0)) -// assert(3 == test(1, 2, 3)) -// -// fn test(a, b, c) { -// return a || b || c -// } -// assert(0 == test(0, 0, 0)) -// assert(1 == test(0, 1, 2)) -// assert(2 == test(0, 0, 2)) -// -// assert(true || false && false) -// assert(!(true && (false || false))) -// assert(!((2 == 3) || (4 < 0) && (1 == 1))) -//} +// Chain ('?') expressions: +{ + fn opt(b: bool) -> Option[int] { + if b { + return Option[int]::Some(1) + } else { + return Option[int]::None() + } + } + { + let hit = false + fn test() -> Option[int] { + let o = opt(true)? + hit = true + return o + } + test() + assert(hit) + } + + { + fn test() -> Option[int] { + let o = opt(false)? + assert(false) + return o + } + test() + } + + fn opt[T](b: bool, v: T) -> Option[T] { + if b { + return Option[T]::Some(v) + } else { + return Option[T]::None() + } + } + + { + fn test[T](v: T) -> Option[T] { + let o = opt(false, v)? + assert(false) + return o + } + test(123) + test('abc') + } + + fn res(b: bool) -> Result[int, string] { + if b { + return Result[int, string]::Ok(42) + } else { + return Result[int, string]::Err('bad') + } + } + + { + let hit = false + fn test() -> Result[int, string] { + let r = res(true)? + hit = true + return r + } + test() + assert(hit) + } + + { + fn test() -> Result[int, string] { + let r = res(false)? + assert(false) + return r + } + test() + } + +} diff --git a/test/scripts/integer.paw b/test/scripts/integer.paw index 53d52dd..c2789bd 100644 --- a/test/scripts/integer.paw +++ b/test/scripts/integer.paw @@ -1,8 +1,8 @@ --- integer.paw +// integer.paw --- Test integer parsing: +// Test integer parsing: { - -- Non-decimal integers + // Non-decimal integers assert(0b0 == 0) assert(0o0 == 0) assert(0x0 == 0) @@ -13,23 +13,10 @@ assert(0o1234 == 668) assert(0x5678 == 22136) - -- Big integers - let x = 84239104721385906132784917234 - assert(x == 0b1000100000011000011110100010010010101101110100111100100011100011110011001111011100010101011110010) - assert(x == 0o104030364222556474434363173425362) - assert(x == 0x11030F4495BA791C799EE2AF2) - - let x = 0x100000000000000000000000 -- 93-bit integer - let y = 4951760157141521099596496896 -- 'x' as decimal - let z = 0x11111111111111111111111111111111111111 - assert(x == y) - assert(x != z) - assert(y != z) - assert(int('-100') < 0) assert(int('100') > 0) - fn ok_integer(str, f) { + fn ok_integer(str: string, f) { assert(int(str) == f) } @@ -54,152 +41,7 @@ bad_integer('1.1') } --- Test big integers: -{ - let ivalues = [ - 0, - 111111111111111111111111, - 222222222222222222222222, - 333333333333333333333333, - 444444444444444444444444, - 555555555555555555555555, - 666666666666666666666666, - 777777777777777777777777, - 888888888888888888888888, - 999999999999999999999999, - ] - fn I(i) { - assert(i >= 0 && i < #ivalues) - return ivalues[i] - } - assert(I(1) > (1 << 64)) - - -- Test bigint '+': - { - assert( I(0) + I(1) == I(1)) - assert( I(1) + I(2) == I(3)) - assert( I(1) + -I(2) == -I(1)) - assert(-I(1) + I(2) == I(1)) - assert(-I(1) + -I(2) == -I(3)) - } - - -- Test bigint '-': - { - assert( I(0) - I(1) == -I(1)) - assert( I(1) - I(2) == -I(1)) - assert( I(1) - -I(2) == I(3)) - assert(-I(1) - I(2) == -I(3)) - assert(-I(1) - -I(2) == I(1)) - } - - -- Test bigint '*': - { - -- (i * 0) == (0 * i) == 0 - assert(0 * I(1) == 0) - assert(I(1) * 0 == 0) - - -- (i * 1) == (1 * i) == i - assert(1 * I(2) == I(2)) - assert(I(2) * 1 == I(2)) - - -- (i * n) == (n * i) == i + ... (n - 1 additions) - assert(I(2) * 3 == I(2) + I(2) + I(2)) - assert(I(3) * 4 == I(3) + I(3) + I(3) + I(3)) - assert(3 * I(2) == I(2) + I(2) + I(2)) - assert(4 * I(3) == I(3) + I(3) + I(3) + I(3)) - - -- (i+j) * (i+j) == i*i + 2*i*j + j*j - fn check(i, j) { - let lhs = (I(i) + I(j)) * (I(i) + I(j)) - let rhs = I(i) * I(i) + 2 * I(i) * I(j) + I(j) * I(j) - assert(lhs == rhs) - } - check(1, 2) - check(2, 3) - } - - -- Test bigint '//': - { - assert(I(9) // 3 == I(3)) - assert(I(9) // I(3) == 3) - assert(I(9) // I(2) == 4) - assert(I(5) // I(4) == 1) - assert(I(4) // I(5) == 0) - assert(I(9) // 23 == 43478260869565217391304) - } - - -- Test bigint bitwise operators: - { - fn check(x, y) { - assert(x == y) - } - let x = 0b10011101000001110011101011000101110001001000010010001000000011010 - let y = 0b10001100000100011011011001111001000111001101110010100000001110110 - - check(!x, false) - check(-x, -0b10011101000001110011101011000101110001001000010010001000000011010) - check(~x, -0b10011101000001110011101011000101110001001000010010001000000011011) - check(x | y, 0b10011101000101111011111011111101110111001101110010101000001111110) - check(x & y, 0b10001100000000010011001001000001000001001000010010000000000010010) - check(x ^ y, 0b00010001000101101000110010111100110110000101100000101000001101100) - check(~(x & y), -0b10001100000000010011001001000001000001001000010010000000000010011) - } - - { - let v = 33232930569601 * 33232930569601 - assert(v == 1104427674243920646305299201) - assert(v * 1 == v) - assert(v * 0 == 0) - assert(1 * v == v) - assert(0 * v == 0) - } - - { - let n = 102934891052780914810295901234976854378 - let qr = [ - null, - null, - [51467445526390457405147950617488427189, 0], - [34311630350926971603431967078325618126, 0], - [25733722763195228702573975308744213594, 2], - [20586978210556182962059180246995370875, 3], - [17155815175463485801715983539162809063, 0], - [14704984436111559258613700176425264911, 1], - [12866861381597614351286987654372106797, 2], - [11437210116975657201143989026108539375, 3], - [10293489105278091481029590123497685437, 8], - [9357717368434628619117809203179714034, 4], - [8577907587731742900857991769581404531, 6], - [7918068542521608831561223171921296490, 8], - [7352492218055779629306850088212632455, 8], - [6862326070185394320686393415665123625, 3], - [6433430690798807175643493827186053398, 10], - [6054993591340053812370347131469226728, 2], - [5718605058487828600571994513054269687, 12], - [5417625844883206042647152696577729177, 15], - [5146744552639045740514795061748842718, 18], - [4901661478703853086204566725475088303, 15], - [4678858684217314309558904601589857017, 4], - [4475430045773083252621560923259863233, 19], - [4288953793865871450428995884790702265, 18], - ] - for d = 2,#qr { - let q = qr[d][0] - let r = qr[d][1] - assert(n // d == q) - assert(d // n == 0) - assert(0 // n == 0) - assert(n // n == 1) - assert(n % d == r) - assert(d % n == d) - assert(n % n == 0) - assert(0 % n == 0) - } - } - -} - --- More tests for big integers and boundary values +// Boundary values { fn apply(f, target) { for t in target { @@ -218,7 +60,7 @@ } let ismall = [ - -70368744177663 - 1, -- PAW_INT_MIN + -70368744177663 - 1, // PAW_INT_MIN -73748835532, -8835532, -532, @@ -228,19 +70,19 @@ 407, 4073748, 40737488355, - 70368744177663, -- PAW_INT_MAX + 70368744177663, // PAW_INT_MAX ] let ilarge = [ -90121909996521879321156109823471015, -488124578190375084952901, - -70368744177665, -- PAW_INT_MIN - 1 - 70368744177664, -- PAW_INT_MAX + 1 + -70368744177665, // PAW_INT_MIN - 1 + 70368744177664, // PAW_INT_MAX + 1 201767997902333542592493, 82040031098795190476449481359582068, ] - -- Precedence helper + // Precedence helper fn check(x, y) { assert(x == y) } @@ -252,10 +94,10 @@ check(~x, ~~~x) check(-x, - - -x) - -- Relationship between '-' and '~': + // Relationship between '-' and '~': check(~x, -x - 1) - -- Identity property: + // Identity property: check(x * 1, x) check(x + 0, x) @@ -263,12 +105,12 @@ check(x << 2, x * 4) check(x << 3 >> 1, x << 2) - -- 'y' must be a bigint + // 'y' must be a bigint let y = x << 50; check(y >> 50, x) if x < 0 { - -- Right shift does sign extension + // Right shift does sign extension check(x >> 10000, -1) } else { check(x >> 10000, 0) @@ -279,19 +121,19 @@ let x = a[0] let y = a[1] - -- Commutative property: + // Commutative property: check(x + y, y + x) check(x * y, y * x) - -- Associative property: + // Associative property: check(x + (y + x), (x + y) + x) check(x * (y * x), (x * y) * x) - -- Distributive property: + // Distributive property: check(x * (x + y), x * x + x * y) check(x * (x - y), x * x - x * y) - -- Variations/other checks: + // Variations/other checks: check(x - y, -y + x) check(x + y + y, x + 2 * y) check(x + x + y + y + y, 2 * x + 3 * y) @@ -316,7 +158,7 @@ let x = a[0] let y = a[1] - -- De Morgan's laws + // De Morgan's laws check(~(x & y), (~x | ~y)) check(~(x | y), (~x & ~y)) } diff --git a/test/scripts/loop.paw b/test/scripts/loop.paw index 63a4b63..4da4d7f 100644 --- a/test/scripts/loop.paw +++ b/test/scripts/loop.paw @@ -1,471 +1,520 @@ // loop.paw -for i = 0, 8 { - let a = -1 - let b = -1 +{ + for i = 0, 8 { + let a = -1 + let b = -1 + } } -//// Make sure loop code cleans the stack up when finished +// Make sure loop code cleans the stack up when finished +{ + for i = 1, 8 { + for j = 1, i {} + } + fn test() -> int {return 123} + assert(test() == 123) +} + +// Numeric for loop: +{ + fn test(start: int, end: int, step: int) -> int { + let n = 0 + for i = start, end, step { + n = n + 1 + } + return n + } + assert(test(0, 0, 1) == 0) + assert(test(0, 0, -1) == 0) + assert(test(0, -1, 1) == 0) + assert(test(0, 1, -1) == 0) + assert(test(0, 0, 10) == 0) + assert(test(0, 0, -10) == 0) + assert(test(0, -1, 10) == 0) + assert(test(0, 1, -10) == 0) + + assert(test(-1, 1, 1) == 2) + assert(test(-10, 10, 1) == 20) + assert(test(1, -1, -1) == 2) + assert(test(10, -10, -1) == 20) + assert(test(-1, 1, 2) == 1) + assert(test(-10, 10, 2) == 10) + assert(test(1, -1, -2) == 1) + assert(test(10, -10, -2) == 10) + assert(test(-1, 1, 4) == 1) + assert(test(-10, 10, 4) == 5) + assert(test(1, -1, -4) == 1) + assert(test(10, -10, -4) == 5) + + // Loop bounds are copied onto the stack when the loop starts. Changing them + // during the loop has no effect. + let n = 0 + let N = 10 + for i = 0, N { + n = n + 1 + N = 0 + } + assert(n == 10) + + fn test(n: int) -> fn() -> int { + fn default() -> int { + return -1 + } + let f = default + for i = 0, 100 { + if i == n { + // Capture 'i', the loop variable, when it is equal to 'n'. It should + // retain this value in the closure, since 'i' is closed over at the + // end of the loop iteration. + fn closure() -> int { + return i + } + f = closure + } + } + return f + } + assert(test(0)() == 0) + assert(test(10)() == 10) + assert(test(50)() == 50) + assert(test(100)() == -1) +} +{ + let a = 'A' + let b = 'B' + for i = 0, 100 { + let b = 'C' + let c = 'C' + let d = 'D' + a = c + b = d // 'b' shadowed + if i == 10 { + break + } else { + continue + } + } + let a = a + let b = b + assert(a == 'C') + assert(b == 'B') +} +{ + for i = 0, 8 { + for j = 0, i { + for k = j, 8 { + assert(j < i) + assert(j <= k) + } + } + } +} + +// TODO: Get this working, once data structures are working again +//// Iterator for loop: //{ -// for i = 1, 8 { -// for j = 1, i {} +// let i = 1 +// for e in [1, 2, 3] { +// assert(e == i) +// i = i + 1 // } -// fn test() -> int {return 123} -// assert(test() == 123) -//} // -//// Numeric for loop: -//{ -// fn test(start: int, end: int, step: int) -> int { -// let n = 0 -// for i = start, end, step { -// n = n + 1 -// } -// return n +// let i = 0 +// for k in {1: 1, 2: 2, 3: 3} { +// i = i + 1 // } -// assert(test(0, 0, 1) == 0) -// assert(test(0, 0, -1) == 0) -// assert(test(0, -1, 1) == 0) -// assert(test(0, 1, -1) == 0) -// assert(test(0, 0, 10) == 0) -// assert(test(0, 0, -10) == 0) -// assert(test(0, -1, 10) == 0) -// assert(test(0, 1, -10) == 0) +// assert(i == 3) // -// assert(test(-1, 1, 1) == 2) -// assert(test(-10, 10, 1) == 20) -// assert(test(1, -1, -1) == 2) -// assert(test(10, -10, -1) == 20) -// assert(test(-1, 1, 2) == 1) -// assert(test(-10, 10, 2) == 10) -// assert(test(1, -1, -2) == 1) -// assert(test(10, -10, -2) == 10) -// assert(test(-1, 1, 4) == 1) -// assert(test(-10, 10, 4) == 5) -// assert(test(1, -1, -4) == 1) -// assert(test(10, -10, -4) == 5) +// let a = [1, 2, 3] +// let b: [int] +// for e in a { +// b.push(e) +// a.pop() +// } +// assert(#b == 2) +// assert(b[0] == 1) +// assert(b[1] == 2) +//} + +// While loop: +{ + fn test(n: int) -> int { + let count = 0 + while count < n { + count = count + 1 + } + return count + } + assert(test(0) == 0) + assert(test(1) == 1) + assert(test(10) == 10) +} + +// Do-while loop: +{ + let i = 0 + do { + i = i + 1 + } while i < 10 + + assert(i == 10) + + do { + i = 42 + } while false + + assert(i == 42) +} + +// 'break' and 'continue' statements: +{ + let n = -1 + for i = 0,3 { + if i == 2 { + break + } + n = i + } + assert(n == 1) + + let n = -1 + for i = 0,3 { + if i == 2 { + continue + } + n = i + } + assert(n == 1) + + // Capture loop variable 'i' as an upvalue. + fn test(n: int) -> fn() -> int { + fn default() -> int { + return -1 + } + let f = default + for i = 0,100 { + if i == n { + let u = i + fn closure() -> int { + return n + i + u + } + f = closure + break + } + } // 'i' closed here when i == n, popped otherwise + return f + } + assert(test(0)() == 0) + assert(test(10)() == 30) + assert(test(50)() == 150) + assert(test(100)() == -1) + + let i = 0 + do { + i = i + 1 + break + } while true + + assert(i == 1) + + let i = 0 + do { + if i == 10 { + break + } + i = i + 1 + } while true + + assert(i == 10) + + let i = 0 + do { + i = i + 1 + continue + } while i < 10 + + assert(i == 10) + + let i = 0 + let n = 0 + do { + i = i + 1 + if i & 1 != 0 { + continue + } + n = n + 1 + } while i < 10 + + assert(n == 5) + + let i = 0 + let n = 0 + do { + i = i + 1 + if i & 1 != 0 { + continue + } else if i == 10 { + break + } + n = n + 1 + } while true + + assert(n == 4) +} + +{ + let n = 0 + let N = 10 + for i = 0, N { + n = n + 1 + N = 0 + } + assert(n == 10) +} + +//{ +// let N = 2 // -// // Loop bounds are copied onto the stack when the loop starts. Changing them -// // during the loop has no effect. -// let n = 0 -// let N = 10 -// for i = 0, N { -// n = n + 1 -// N = 0 +// let a = [] +// for i = 0,N { +// for j in [0] { +// a.push(i + j) +// } // } -// assert(n == 10) +// assert(#a == 2) +// assert(a[0] == 0) +// assert(a[1] == 1) // -// fn test(n: int) -> fn() -> int { -// fn default() -> int { -// return -1 +// let a = [] +// for i = 0, N { +// let j = 0 +// while j < N { +// a.push(i + j) +// j = j + 1 // } -// let f = default -// for i = 0, 100 { -// if i == n { -// // Capture 'i', the loop variable, when it is equal to 'n'. It should -// // retain this value in the closure, since 'i' is closed over at the -// // end of the loop iteration. -// fn closure() -> int { -// return i -// } -// f = closure +// } +// assert(#a == 4) +// assert(a[0] == 0) +// assert(a[1] == 1) +// assert(a[2] == 1) +// assert(a[3] == 2) +// +// let a = [] +// for i = 0,N { +// for j in [0] { +// let k = 0 +// while k < N { +// a.push(i + j + k) +// k = k + 1 // } // } -// return f // } -// assert(test(0)() == 0) -// assert(test(10)() == 10) -// assert(test(50)() == 50) -// assert(test(100)() == -1) +// assert(#a == 4) +// assert(a[0] == 0) +// assert(a[1] == 1) +// assert(a[2] == 1) +// assert(a[3] == 2) //} -// -//// TODO: Get this working, once data structures are working again -////// Iterator for loop: -////{ -//// let i = 1 -//// for e in [1, 2, 3] { -//// assert(e == i) -//// i = i + 1 -//// } -//// -//// let i = 0 -//// for k in {1: 1, 2: 2, 3: 3} { -//// i = i + 1 -//// } -//// assert(i == 3) -//// -//// let a = [1, 2, 3] -//// let b: [int] -//// for e in a { -//// b.push(e) -//// a.pop() -//// } -//// assert(#b == 2) -//// assert(b[0] == 1) -//// assert(b[1] == 2) -////} -// -//// While loop: + +{ + let n = 0 + for i = 0,8 { + n = n + 1 + break + } + assert(n == 1) +} + +{ + fn test(n: int) -> int { + let count = 0 + for i = 0,100 { + if i == n { + break + } + count = count + 1 + continue + } + return count + } + assert(test(-1) == 100) + assert(test(0) == 0) + assert(test(25) == 25) + assert(test(50) == 50) +} + +{ + let i = -1 + + // 'i' shadowed by loop variable. + for i = 0,8 {} + assert(i == -1) +} + //{ -// fn test(n: int) -> int { -// let count = 0 -// while count < n { -// count = count + 1 -// } -// return count +// // Invalid operations must be run to throw an exception +// if false && 1 / 0 { +// let x = 1 / 0 +// let y = 1 % 0 // } -// assert(test(0) == 0) -// assert(test(1) == 1) -// assert(test(10) == 10) //} -// -//// Do-while loop: -//{ -// let i = 0 -// do { -// i = i + 1 -// } while i < 10 -// -// assert(i == 10) -// -// do { -// i = 42 -// } while false -// -// assert(i == 42) -//} -// -//// 'break' and 'continue' statements: + //{ -// let n = -1 -// for i = 0,3 { -// if i == 2 { -// break -// } -// n = i -// } -// assert(n == 1) -// -// let n = -1 -// for i = 0,3 { -// if i == 2 { -// continue -// } -// n = i -// } -// assert(n == 1) -// -// // Capture loop variable 'i' as an upvalue. -// fn test(n: int) -> fn() -> int { -// fn default() -> int { -// return -1 -// } -// let f = default -// for i = 0,100 { -// if i == n { -// let u = i -// fn closure() -> int { -// return n + i + u -// } -// f = closure -// break -// } -// } // 'i' closed here when i == n, popped otherwise -// return f +// let I = [0, 1, 2, 3] +// for i = 0,4 { +// assert(i == I[i]) // } -// assert(test(0)() == 0) -// assert(test(10)() == 30) -// assert(test(50)() == 150) -// assert(test(100)() == -1) // -// let i = 0 -// do { -// i = i + 1 -// break -// } while true -// -// assert(i == 1) -// -// let i = 0 -// do { -// if i == 10 { -// break -// } -// i = i + 1 -// } while true -// -// assert(i == 10) -// -// let i = 0 -// do { -// i = i + 1 -// continue -// } while i < 10 -// -// assert(i == 10) -// -// let i = 0 // let n = 0 -// do { -// i = i + 1 -// if i & 1 != 0 { -// continue -// } +// let I = [2, 3] +// for i = 2,4 { +// assert(i == I[n]) // n = n + 1 -// } while i < 10 -// -// assert(n == 5) -// -// let i = 0 -// let n = 0 -// do { -// i = i + 1 -// if i & 1 != 0 { -// continue -// } else if i == 10 { -// break -// } -// n = n + 1 -// } while true -// -// assert(n == 4) -//} -// -//{ -// let n = 0 -// let N = 10 -// for i = 0, N { -// n = n + 1 -// N = 0 // } -// assert(n == 10) -//} // -////{ -//// let N = 2 -//// -//// let a = [] -//// for i = 0,N { -//// for j in [0] { -//// a.push(i + j) -//// } -//// } -//// assert(#a == 2) -//// assert(a[0] == 0) -//// assert(a[1] == 1) -//// -//// let a = [] -//// for i = 0, N { -//// let j = 0 -//// while j < N { -//// a.push(i + j) -//// j = j + 1 -//// } -//// } -//// assert(#a == 4) -//// assert(a[0] == 0) -//// assert(a[1] == 1) -//// assert(a[2] == 1) -//// assert(a[3] == 2) -//// -//// let a = [] -//// for i = 0,N { -//// for j in [0] { -//// let k = 0 -//// while k < N { -//// a.push(i + j + k) -//// k = k + 1 -//// } -//// } -//// } -//// assert(#a == 4) -//// assert(a[0] == 0) -//// assert(a[1] == 1) -//// assert(a[2] == 1) -//// assert(a[3] == 2) -////} -// -//{ // let n = 0 -// for i = 0,8 { +// let I = [1, 3] +// for i = 1,4,2 { +// assert(i == I[n]) // n = n + 1 -// break -// } -// assert(n == 1) -//} -// -//{ -// fn test(n: int) -> int { -// let count = 0 -// for i = 0,100 { -// if i == n { -// break -// } -// count = count + 1 -// continue -// } -// return count // } -// assert(test(-1) == 100) -// assert(test(0) == 0) -// assert(test(25) == 25) -// assert(test(50) == 50) //} -// -//{ -// let i = -1 -// -// // 'i' shadowed by loop variable. -// for i = 0,8 {} -// assert(i == -1) -//} -// -////{ -//// // Invalid operations must be run to throw an exception -//// if false && 1 / 0 { -//// let x = 1 / 0 -//// let y = 1 % 0 -//// } -////} -// -////{ -//// let I = [0, 1, 2, 3] -//// for i = 0,4 { -//// assert(i == I[i]) -//// } -//// -//// let n = 0 -//// let I = [2, 3] -//// for i = 2,4 { -//// assert(i == I[n]) -//// n = n + 1 -//// } -//// -//// let n = 0 -//// let I = [1, 3] -//// for i = 1,4,2 { -//// assert(i == I[n]) -//// n = n + 1 -//// } -////} -// + +{ + let n = 0 + for i = 0, 8 { + n = n + 1 + break + } + assert(n == 1) +} + +// TODO: This is a syntax error (stops compilation), check in test_error.c //{ // let n = 0 // for i = 0, 8 { // n = n + 1 -// break -// } -// assert(n == 1) -//} -// -//// TODO: This is a syntax error (stops compilation), check in test_error.c -////{ -//// let n = 0 -//// for i = 0, 8 { -//// n = n + 1 -//// continue -//// -//// // unreachable -//// assert(false) -//// } -//// assert(n == 8) -////} -// -////{ -//// fn test(n: int) -> int { -//// let f -//// for i = 0, 100 { -//// if i == n {{{ // <-- NOTE: Nested blocks here -//// let a = [i] -//// fn check() { -//// // Capture 'a' as an upvalue. -//// let m = a[0] -//// a[0] = a[0] + 1 -//// // Equivalent to '3 * n' on the first call. Increases by 1 -//// // each time. -//// return i + n + m -//// } -//// f = check -//// break -//// }}} -//// } -//// return f -//// } -//// assert(test(-1) == null) -//// -//// let t = test(10) -//// assert(t() == 30) -//// assert(t() == 31) -//// assert(t() == 32) -////} -// -//{ -// fn test(b: bool) -> int { -// fn hack() -> int {return -1} // TODO: Option[T] type, then this is not necessary -// let f = hack -// let n = 0 -// for i = 0,8 { -// let _0 = -1 -// let _1 = -1 -// { -// let _2 = -1 -// -// n = n + 1 -// let m = n -// fn closure() -> int { -// return m + n -// } -// f = closure -// // Need to emit instructions to close 'm' at the break and continue -// // statements. -// if b { -// break -// } else { -// continue -// } -// let _3 = -1 -// } -// let _4 = -1 -// let _5 = -1 -// } -// return f() +// continue +// +// // unreachable +// assert(false) // } -// assert(test(true) == 2) -// assert(test(false) == 16) +// assert(n == 8) //} -// + //{ // fn test(n: int) -> int { -// fn hack() -> int {return -1} // TODO: Option[T] type, then this is not necessary -// let f = hack -// for _ = 0, 10 { -// if n == 0 { -// let _0 = 0 -// fn closure() -> int {return n + _0} -// f = closure -// break -// } else if n == 1 { -// if n == 1 { -// let _1 = 1 -// fn closure() -> int {return n + _1} -// f = closure -// break -// } -// } else if n == 2 { -// if n == 2 { -// if n == 2 { -// let _2 = 2 -// fn closure() -> int {return n + _2} -// f = closure -// break -// } +// let f +// for i = 0, 100 { +// if i == n {{{ // <-- NOTE: Nested blocks here +// let a = [i] +// fn check() { +// // Capture 'a' as an upvalue. +// let m = a[0] +// a[0] = a[0] + 1 +// // Equivalent to '3 * n' on the first call. Increases by 1 +// // each time. +// return i + n + m // } -// } +// f = check +// break +// }}} // } -// return f() +// return f // } -// assert(test(0) == 0) -// assert(test(1) == 2) -// assert(test(2) == 4) -//} +// assert(test(-1) == null) // +// let t = test(10) +// assert(t() == 30) +// assert(t() == 31) +// assert(t() == 32) +//} + +{ + fn test(b: bool) -> int { + fn hack() -> int {return -1} // TODO: Option[T] type, then this is not necessary + let f = hack + let n = 0 + for i = 0,8 { + let _0 = -1 + let _1 = -1 + { + let _2 = -1 + + n = n + 1 + let m = n + fn closure() -> int { + return m + n + } + f = closure + // Need to emit instructions to close 'm' at the break and continue + // statements. + if b { + break + } else { + continue + } + let _3 = -1 + } + let _4 = -1 + let _5 = -1 + } + return f() + } + assert(test(true) == 2) + assert(test(false) == 16) +} + +{ + fn test(n: int) -> int { + fn hack() -> int {return -1} // TODO: Option[T] type, then this is not necessary + let f = hack + for _ = 0, 10 { + if n == 0 { + let _0 = 0 + fn closure() -> int {return n + _0} + f = closure + break + } else if n == 1 { + if n == 1 { + let _1 = 1 + fn closure() -> int {return n + _1} + f = closure + break + } + } else if n == 2 { + if n == 2 { + if n == 2 { + let _2 = 2 + fn closure() -> int {return n + _2} + f = closure + break + } + } + } + } + return f() + } + assert(test(0) == 0) + assert(test(1) == 2) + assert(test(2) == 4) +} +{ + let a = 42 + while true { + let b = 1 + while true { + break + } + { + assert(b == 1) + break + } + let c = 2 + let d = 3 + } + assert(a == 42) +} + + diff --git a/test/scripts/mandelbrot.paw b/test/scripts/mandelbrot.paw index 42467ab..590e0b8 100644 --- a/test/scripts/mandelbrot.paw +++ b/test/scripts/mandelbrot.paw @@ -1,53 +1,57 @@ --- mandelbrot.paw --- usage: paw mandelbrot.paw x0,x1,nx,y0,y1,ny --- translated from https://rosettacode.org/wiki/Mandelbrot_set#ASCII_2 (Lua). +// mandelbrot.paw +// usage: paw mandelbrot.paw x0,x1,nx,y0,y1,ny +// translated from https://rosettacode.org/wiki/Mandelbrot_set#ASCII_2 (Lua). -let io = require('io') -let file = io.stdout +//let io = require('io') +//let file = io.stdout -let charmap = [ +let charmap = Vector[string]{ ' ', '.', ':', '-', '=', '+', '*', '#', '%', '@', -] - -fn map(f, seq) { - for i = 0, #seq { - seq[i] = f(seq[i]) - } - return seq } -print(argv[0]) -let argv = map(float, argv[1].split(',')) -let x0 = float(argv[0]) -let x1 = float(argv[1]) -let nx = int(argv[2]) -let y0 = float(argv[3]) -let y1 = float(argv[4]) -let ny = int(argv[5]) +//let charmap = [ +// ' ', '.', ':', '-', '=', +// '+', '*', '#', '%', '@', +//] + +//fn map(f, seq) { +// for i = 0, #seq { +// seq[i] = f(seq[i]) +// } +// return seq +//} +//print(argv[0]) +//let argv = map(float, argv[1].split(',')) + +let x0 = -1.8//float(argv[0]) +let x1 = 1.2//float(argv[1]) +let nx = 100//int(argv[2]) +let y0 = -1.3//float(argv[3]) +let y1 = 1.3//float(argv[4]) +let ny = 32//int(argv[5]) assert(nx > 0 && ny > 0) -let dy = (y1 - y0) / (ny - 1) -let dx = (x1 - x0) / (nx - 1) +let dy = (y1 - y0) / float(ny - 1) +let dx = (x1 - x0) / float(nx - 1) for i = 0, ny { - let y = y0 + i * dy + let y = y0 + float(i) * dy for j = 0, nx { - let x = x0 + j * dx - let zi = 0 - let zr = 0 + let x = x0 + float(j) * dx + let zi = 0.0 + let zr = 0.0 let i = 0 while i < 100 { - if zi*zi+zr*zr >= 4 { + if zi*zi+zr*zr >= 4.0 { break } let zz = zr*zr - zi*zi + x - zi = 2*zr*zi + y + zi = 2.0*zr*zi + y zr = zz i = i + 1 } - io.write(file, charmap[i % 10]) + print(charmap[i % 10]) } - io.write(file, '\n') + print('\n') } -io.flush(file) diff --git a/test/scripts/operator.paw b/test/scripts/operator.paw index 03fd253..cc4cb40 100644 --- a/test/scripts/operator.paw +++ b/test/scripts/operator.paw @@ -67,41 +67,3 @@ assert(0b0010 == (0b0110 & 0b0011)) assert(0b0101 == (0b0110 ^ 0b0011)) } - -// Conditional expressions: -{ - assert('true' == (true ?? 'true' :: 'false')) - assert('false' == (false ?? 'true' :: 'false')) - - assert('true' == (1 + 1 + 1 == 3 ?? 'true' :: 'false')) - assert('false' == (0 + 0 + 0 == 3 ?? 'true' :: 'false')) - - assert(42 == (true ?? 40 + 2 :: 0)) - assert(0 == (false ?? 40 + 2 :: 0)) - assert(42 == (false ?? 0 :: 40 + 2)) - assert(0 == (true ?? 0 :: 40 + 2)) - - assert(0 == (true ?? 0 :: false ?? 1 :: 2)) - assert(1 == (false ?? 0 :: true ?? 1 :: 2)) - assert(2 == (false ?? 0 :: false ?? 1 :: 2)) - - assert(0 == (true ?? true ?? 0 :: 1 :: 2)) - assert(1 == (true ?? false ?? 0 :: 1 :: 2)) - assert(2 == (false ?? false ?? 0 :: 1 :: 2)) - - let x = false ?? 1 :: 0 - assert(x == 0) - let x = true ?? 1 :: 0 - assert(x == 1) - - fn test(v: int) -> int { - return v == 1 ?? 10 :: - v == 2 ?? 20 :: - v == 3 ?? 30 :: 40 - } - assert(40 == test(0)) - assert(10 == test(1)) - assert(20 == test(2)) - assert(30 == test(3)) - assert(40 == test(4)) -} diff --git a/test/scripts/string.paw b/test/scripts/string.paw index c5681a0..126b30d 100644 --- a/test/scripts/string.paw +++ b/test/scripts/string.paw @@ -1,4 +1,4 @@ --- string.paw +// string.paw { assert(!'') @@ -52,23 +52,23 @@ // assert(s[3:] == '') // assert(s[0:0] == '') // -// -- clamped +// // clamped // assert(s[4:] == '') // assert(s[:-4] == '') //} - --- String find: -{ - fn check(s: string, sub: string, n: int) { - assert(n == s.find(sub)) - } - check('abc', 'a', 0) - check('abc', 'b', 1) - check('abc', 'c', 2) - check('abc', 'd', -1) -} - -//-- String split/join: +// +//// String find: +//{ +// fn check(s: string, sub: string, n: int) { +// assert(n == s.find(sub)) +// } +// check('abc', 'a', 0) +// check('abc', 'b', 1) +// check('abc', 'c', 2) +// check('abc', 'd', -1) +//} +// +//// String split/join: //{ // fn check(s, sep, parts) { // let a = s.split(sep) diff --git a/test/scripts/types.paw b/test/scripts/types.paw index 83ba6bf..e6e372e 100644 --- a/test/scripts/types.paw +++ b/test/scripts/types.paw @@ -40,6 +40,42 @@ let x = x + 23 assert(x == 123) } +// Primitive conversion operators: +{ + let b = bool(0) + assert(b == false) + let b = bool(1) + assert(b == true) + let b = bool(-11) + assert(b == true) + + let b = bool(0.0) + assert(b == false) + let b = bool(0.1) + assert(b == true) + + let i = int(1.0) + assert(i == 1) + let i = int(1.9) + assert(i == 1) + let i = int(-1.9) + assert(i == -1) + + let f = float(1) + assert(f < 1.1) + let f = float(-10) + assert(f > -10.1) + + let i = 0 + let b = bool(i) + let i = int(b) + assert(i == 0) + + let i = 1234 + let b = bool(i) + let i = int(b) + assert(i == 1) +} //*********************************************** // functions @@ -444,3 +480,110 @@ assert(3.0 == new_pair(2.0, 3.0).second) assert('five' == new_pair('four', 'five').second) } + +//*********************************************** +// tuples +//*********************************************** +{ + let t0 = () + let p1 = (false) + let t1 = (false,) + let t2 = (false, 1) + + // Empty: unit type + let t0: () = t0 + + // No comma: parenthesized expression + let p1: bool = p1 + + let t1: (bool,) = t1 + let t2: (bool, int) = t2 +} +{ + let t1 = (false,) + let t2 = (false, 1) + let t3 = (false, 1, 2.0) + let t4 = (false, 1, 2.0, 'three') + assert(t1.0 == t2.0 && t2.0 == t3.0 && t3.0 == t4.0 && t4.0 == false) + assert(t2.1 == t3.1 && t3.1 == t4.1 && t4.1 == 1) + assert(t3.2 == t4.2 && t4.2 == 2.0) + assert(t4.3 == 'three') +} +{ + fn test(t: (int, string)) -> (int, string) { + let r = t // copy reference + r.0 = r.0 * 2 + r.1 = r.1 + r.1 + return t + } + let t = test((1, 'two')) + assert(t.0 == 2) + assert(t.1 == 'twotwo') +} +{ + struct Test[T] { + v: (T, T) + } + let t = Test[int]{v: (1, 2)} + assert(t.v.0 == 1) + assert(t.v.1 == 2) +} + +//*********************************************** +// enumerations +//*********************************************** +{ + enum E { + X, + } + let e = E::X() + e = E::X() +} +{ + enum E { + X, + Y, + } + let e = E::X() + e = E::Y() +} +{ + enum E { + X, + Y(int), + } + let e = E::X() + e = E::Y(42) + + fn test(e: E) -> E { + let e2 = e + return e2 + } + let e = test(E::X()) + let e = test(E::Y(42)) + +} +{ + enum E[T] { + X(T), + Y(T, T), + } + let ex = E[int]::X(1) + let ey = E[int]::Y(2, 3) + + fn test(e: E[int]) -> E[int] { + let e2 = e + return e2 + } + test(ex) + test(ey) + + struct S[T] { + x: E[int] + y: E[T] + } + let s = S[float]{ + x: E[int]::X(1), + y: E[float]::Y(2.0, 3.0), + } +} diff --git a/test/test_rt.c b/test/test_rt.c index 4aa1420..668c29b 100644 --- a/test/test_rt.c +++ b/test/test_rt.c @@ -8,12 +8,14 @@ static void script(const char *name) int main(void) { - script("types"); script("basic"); + return 0; + script("types"); script("block"); script("loop"); script("operator"); script("vector"); + script("mandelbrot"); return 0; // TODO script("string"); script("integer");