diff --git a/.vscode/settings.json b/.vscode/settings.json index 2f9bd90..f2a4425 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -83,6 +83,7 @@ "set": "cpp", "unordered_set": "cpp", "source_location": "cpp", - "shared_mutex": "cpp" + "shared_mutex": "cpp", + "strstream": "cpp" }, } \ No newline at end of file diff --git a/compiler/include/AST.h b/compiler/include/AST.h deleted file mode 100644 index ec6162a..0000000 --- a/compiler/include/AST.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include -#include - -class Expr; -class Type; - -typedef std::pair FnArg; - -class ASTNode -{ -}; - -class Stmt : public ASTNode -{ -}; - -class Module : public ASTNode -{ -public: - Module(const std::vector &stmts) : stmts(std::move(stmts)) {} - const std::vector stmts; -}; - -class ValDecl : public Stmt -{ -public: - ValDecl(const std::string &name, const Type *type, const Expr *value) - : name(name), type(type), value(value) {} - - const std::string name; - const Type *type; - const Expr *value; -}; - -class FnDecl : public Stmt -{ -public: - FnDecl(const std::string &name, const std::vector &args, const Type *returnType, const Expr *body) - : name(name), args(std::move(args)), returnType(returnType), body(body) {} - - const std::string name; - const std::vector args; - const Type *returnType; - const Expr *body; -}; - -class Type : public ASTNode -{ -}; - -class TupleType : public Type -{ -public: - TupleType(const std::vector &types) : types(types) {} - const std::vector types; -}; - -class FunctionType : public Type -{ -public: - FunctionType(const std::vector &from, const Type *to) - : from(std::move(from)), to(to) {} - - const std::vector from; - const Type *to; -}; - -class NamedType : public Type -{ -public: - NamedType(const std::string &name) : name(name) {} - const std::string name; -}; - -class Expr : public ASTNode -{ -}; - -class CallExpr : public Expr -{ -public: - CallExpr(const Expr *callee, const std::vector &args) - : callee(callee), args(std::move(args)) {} - - const Expr *callee; - const std::vector args; -}; - -class UnaryExpr : public Expr -{ -public: - UnaryExpr(const std::string &op, const Expr *expr) - : op(op), expr(expr) {} - - const std::string op; - const Expr *expr; -}; - -class BinExpr : public Expr -{ -public: - BinExpr(const Expr *left, const std::string &op, const Expr *right) - : left(left), op(op), right(right) {} - - const Expr *left; - const std::string op; - const Expr *right; -}; - -class PrefExpr : public Expr -{ -public: - PrefExpr(const Expr *expr) : expr(expr) {} - - const Expr *expr; -}; - -class Identifier : public Expr -{ -public: - Identifier(const std::string &name) : name(name) {} - - const std::string name; -}; - -class IntValue : public Expr -{ -public: - IntValue(const long value) : value(value) {} - - const long value; -}; - -class FloatValue : public Expr -{ -public: - FloatValue(const double value) : value(value) {} - - const double value; -}; diff --git a/compiler/include/AST/Base.h b/compiler/include/AST/Base.h new file mode 100644 index 0000000..d70fa28 --- /dev/null +++ b/compiler/include/AST/Base.h @@ -0,0 +1,22 @@ +#pragma once + +namespace ast +{ + class ASTNode + { + public: + virtual ~ASTNode() = default; + }; + + class Expr : public ASTNode + { + }; + + class Stmt : public ASTNode + { + }; + + class Type : public ASTNode + { + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Def.h b/compiler/include/AST/Def.h new file mode 100644 index 0000000..23f9c3f --- /dev/null +++ b/compiler/include/AST/Def.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Base.h" + +#include "Expr/BinExpr.h" +#include "Expr/Block.h" +#include "Expr/Call.h" +#include "Expr/Identifier.h" +#include "Expr/UnaryExpr.h" +#include "Expr/Value.h" + +#include "Stmt/ExprStmt.h" +#include "Stmt/FnDecl.h" +#include "Stmt/ValDecl.h" + +#include "Type/Function.h" +#include "Type/Named.h" +#include "Type/Tuple.h" + +#include "Module/Import.h" +#include "Module/Module.h" diff --git a/compiler/include/AST/Expr/BinExpr.h b/compiler/include/AST/Expr/BinExpr.h new file mode 100644 index 0000000..8709b3b --- /dev/null +++ b/compiler/include/AST/Expr/BinExpr.h @@ -0,0 +1,34 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class BinExpr : public Expr + { + public: + BinExpr(const Expr *left, const std::string &op, const Expr *right) + : left(left), op(op), right(right) {} + + ~BinExpr() + { + delete left; + delete right; + } + + const Expr *left; + const std::string op; + const Expr *right; + }; + + class PrefExpr : public Expr + { + public: + PrefExpr(const Expr *expr) : expr(expr) {} + + ~PrefExpr() { delete expr; } + + const Expr *expr; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Expr/Block.h b/compiler/include/AST/Expr/Block.h new file mode 100644 index 0000000..e9301ce --- /dev/null +++ b/compiler/include/AST/Expr/Block.h @@ -0,0 +1,20 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class BlockExpr : public Expr + { + public: + BlockExpr(const std::vector &stmts) : stmts(std::move(stmts)) {} + ~BlockExpr() + { + for (auto &stmt : stmts) + delete stmt; + } + + const std::vector stmts; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Expr/Call.h b/compiler/include/AST/Expr/Call.h new file mode 100644 index 0000000..1f4a833 --- /dev/null +++ b/compiler/include/AST/Expr/Call.h @@ -0,0 +1,23 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class CallExpr : public Expr + { + public: + CallExpr(const Expr *callee, const std::vector &args) + : callee(callee), args(std::move(args)) {} + + ~CallExpr() + { + for (auto &arg : args) + delete arg; + } + + const Expr *callee; + const std::vector args; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Expr/Identifier.h b/compiler/include/AST/Expr/Identifier.h new file mode 100644 index 0000000..9e36232 --- /dev/null +++ b/compiler/include/AST/Expr/Identifier.h @@ -0,0 +1,15 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class Identifier : public Expr + { + public: + Identifier(const std::string &name) : name(name) {} + + const std::string name; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Expr/UnaryExpr.h b/compiler/include/AST/Expr/UnaryExpr.h new file mode 100644 index 0000000..2e0b2da --- /dev/null +++ b/compiler/include/AST/Expr/UnaryExpr.h @@ -0,0 +1,19 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class UnaryExpr : public Expr + { + public: + UnaryExpr(const std::string &op, const Expr *expr) + : op(op), expr(expr) {} + + ~UnaryExpr() { delete expr; } + + const std::string op; + const Expr *expr; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Expr/Value.h b/compiler/include/AST/Expr/Value.h new file mode 100644 index 0000000..475f2f6 --- /dev/null +++ b/compiler/include/AST/Expr/Value.h @@ -0,0 +1,21 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class IntValue : public Expr + { + public: + IntValue(int64_t value) : value(value) {} + const int64_t value; + }; + + class FloatValue : public Expr + { + public: + FloatValue(double value) : value(value) {} + const double value; + }; +} diff --git a/compiler/include/AST/Module/Import.h b/compiler/include/AST/Module/Import.h new file mode 100644 index 0000000..ec7ef29 --- /dev/null +++ b/compiler/include/AST/Module/Import.h @@ -0,0 +1,14 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class Import : public ASTNode + { + public: + Import(const std::string &moduleName) : moduleName(moduleName) {} + const std::string moduleName; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Module/Module.h b/compiler/include/AST/Module/Module.h new file mode 100644 index 0000000..a25a242 --- /dev/null +++ b/compiler/include/AST/Module/Module.h @@ -0,0 +1,28 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class Import; + + class Module : public ASTNode + { + public: + Module(const std::vector &imports, const std::vector &stmts) + : imports(std::move(imports)), stmts(std::move(stmts)) {} + + ~Module() + { + for (auto &import : imports) + delete import; + + for (auto &stmt : stmts) + delete stmt; + } + + const std::vector &imports; + const std::vector stmts; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Stmt/ExprStmt.h b/compiler/include/AST/Stmt/ExprStmt.h new file mode 100644 index 0000000..a51e5ad --- /dev/null +++ b/compiler/include/AST/Stmt/ExprStmt.h @@ -0,0 +1,15 @@ +#pragma once + +#include "AST/Base.h" + +namespace ast +{ + class ExprStmt : public Stmt + { + public: + ExprStmt(const Expr *expr) : expr(expr) {} + ~ExprStmt() { delete expr; } + + const Expr *expr; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Stmt/FnDecl.h b/compiler/include/AST/Stmt/FnDecl.h new file mode 100644 index 0000000..58eff36 --- /dev/null +++ b/compiler/include/AST/Stmt/FnDecl.h @@ -0,0 +1,31 @@ +#pragma once + +#include "AST/Base.h" +#include +#include + +namespace ast +{ + typedef std::pair FnArg; + + class FnDecl : public Stmt + { + public: + FnDecl(const std::string &name, const std::vector &args, const Type *returnType, const Expr *body) + : name(name), args(std::move(args)), returnType(returnType), body(body) {} + + ~FnDecl() + { + for (auto &arg : args) + delete arg.second; + + delete returnType; + delete body; + } + + const std::string name; + const std::vector args; + const Type *returnType; + const Expr *body; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Stmt/ValDecl.h b/compiler/include/AST/Stmt/ValDecl.h new file mode 100644 index 0000000..783423e --- /dev/null +++ b/compiler/include/AST/Stmt/ValDecl.h @@ -0,0 +1,24 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class ValDecl : public Stmt + { + public: + ValDecl(const std::string &name, const Type *type, const Expr *value) + : name(name), type(type), value(value) {} + + ~ValDecl() + { + delete type; + delete value; + } + + const std::string name; + const Type *type; + const Expr *value; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Type/Function.h b/compiler/include/AST/Type/Function.h new file mode 100644 index 0000000..f1a07b6 --- /dev/null +++ b/compiler/include/AST/Type/Function.h @@ -0,0 +1,25 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class FunctionType : public Type + { + public: + FunctionType(const std::vector &from, const Type *to) + : from(std::move(from)), to(to) {} + + ~FunctionType() + { + for (auto &arg : from) + delete arg; + + delete to; + } + + const std::vector from; + const Type *to; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Type/Named.h b/compiler/include/AST/Type/Named.h new file mode 100644 index 0000000..4b6799b --- /dev/null +++ b/compiler/include/AST/Type/Named.h @@ -0,0 +1,14 @@ +#pragma once + +#include "AST/Base.h" +#include + +namespace ast +{ + class NamedType : public Type + { + public: + NamedType(const std::string &name) : name(name) {} + const std::string name; + }; +} \ No newline at end of file diff --git a/compiler/include/AST/Type/Tuple.h b/compiler/include/AST/Type/Tuple.h new file mode 100644 index 0000000..56c6463 --- /dev/null +++ b/compiler/include/AST/Type/Tuple.h @@ -0,0 +1,21 @@ +#pragma once + +#include "AST/Def.h" +#include + +namespace ast +{ + class TupleType : public Type + { + public: + TupleType(const std::vector &types) : types(std::move(types)) {} + + ~TupleType() + { + for (auto &type : types) + delete type; + } + + const std::vector types; + }; +} \ No newline at end of file diff --git a/compiler/include/ASTVisitor.h b/compiler/include/ASTVisitor.h deleted file mode 100644 index 870f272..0000000 --- a/compiler/include/ASTVisitor.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -#include "AST.h" - -template -class ASTVisitor -{ - virtual T visit(const ASTNode *node) - { - if (IntValue *cnode = dynamic_cast(node)) - return visitIntValue(cnode); - else if (FloatValue *cnode = dynamic_cast(node)) - return visitFloatValue(cnode); - - throw std::logic_error("not implemented"); - } - - virtual T visitIntValue(const IntValue *node); - virtual T visitFloatValue(const IntValue *node); -}; diff --git a/compiler/include/ParserDriver.h b/compiler/include/ParserDriver.h index 454c1ce..4ee54f8 100644 --- a/compiler/include/ParserDriver.h +++ b/compiler/include/ParserDriver.h @@ -2,13 +2,14 @@ #include -#include "AST.h" +#include "AST/Def.h" #include "parser.gen.h" class ParserDriver { public: ParserDriver() {} + ~ParserDriver() { delete module; } int parse(const std::string &input); @@ -17,7 +18,7 @@ public: std::string file; yy::location location; - Module *module; + ast::Module *module; }; #define YY_DECL yy::parser::symbol_type yylex(ParserDriver &driver) diff --git a/compiler/lexer.ll b/compiler/lexer.ll index 7e3b985..16633e9 100644 --- a/compiler/lexer.ll +++ b/compiler/lexer.ll @@ -35,19 +35,24 @@ whitespace [ \n\t\r\v]+ if (text == "->") return _token(RARR); return _token(OPERATOR); } +"." { return _token(DOT); } "," { return _token(COMMA); } ";" { return _token(SEMI); } "(" { return _token(LPAREN); } ")" { return _token(RPAREN); } "[" { return _token(LBRACKET); } "]" { return _token(RBRACKET); } +"{" { return _token(LBRACE); } +"}" { return _token(RBRACE); } -"fn" { return _token(FN); } -"unop" { return _token(UNOP); } "binop" { return _token(BINOP); } -"val" { return _token(VAL); } -"import" { return _token(IMPORT); } "declare" { return _token(DECLARE); } +"fn" { return _token(FN); } +"import" { return _token(IMPORT); } +"trait" { return _token(TRAIT); } +"type" { return _token(TYPE); } +"unop" { return _token(UNOP); } +"val" { return _token(VAL); } {letter}({digit}|{letter})* { return _token(IDENTIFIER); } diff --git a/compiler/parser.yy b/compiler/parser.yy index 8abd49b..f868a9c 100644 --- a/compiler/parser.yy +++ b/compiler/parser.yy @@ -18,7 +18,7 @@ %define api.location.include {"location.gen.h"} %code requires { -#include "AST.h" +#include "AST/Def.h" class ParserDriver; } @@ -38,43 +38,57 @@ class ParserDriver; RARR "->" EQUALS "=" + DOT "." COMMA "," SEMI ";" LPAREN "(" RPAREN ")" LBRACKET "[" RBRACKET "]" + LBRACE "{" + RBRACE "}" - FN "fn" - UNOP "unop" BINOP "binop" - VAL "val" - IMPORT "import" DECLARE "declare" + FN "fn" + IMPORT "import" + TRAIT "trait" + TYPE "type" + UNOP "unop" + VAL "val" ; %token END 0 "end of file" -%type > stmts; -%type - stmt - decl +%type > + topLevelStmts + blockStmts ; -%type fnDecl; -%type valDecl; +%type + topLevelStmt + blockStmt +; -%type +%type extFnDecl fnDecl; +%type valDecl; + +%type > + types + tupleTypes + fnTypeArgs +; + +%type type - type0 ; -%type > +%type > exprs args ; -%type +%type expr expr3 expr2 @@ -83,8 +97,8 @@ class ParserDriver; literal ; -%type fnArg; -%type > +%type fnArg; +%type > fnArgs fnArgs0 ; @@ -95,53 +109,100 @@ class ParserDriver; ; %type + moduleName operator identifier keyword ; +%type import; +%type > + imports0 + imports +; + %start module %% -module: stmts END { driver.module = new Module($1); }; - -stmts: stmt { $$ = std::vector(); $$.push_back($1); } - | stmts stmt { $1.push_back($2); $$ = std::move($1); } - ; - -stmt: decl; - -decl: valDecl { $$ = $1; } - | fnDecl { $$ = $1; } - ; - -valDecl: VAL identifier "=" expr ";" { $$ = new ValDecl($2, nullptr, $4); } - | VAL identifier type "=" expr ";" { $$ = new ValDecl($2, $3, $5); } - ; - -fnDecl: FN identifier "[" fnArgs "]" type "=" expr ";" { $$ = new FnDecl($2, $4, $6, $8); } +module: imports topLevelStmts { driver.module = new ast::Module($2); } ; -fnArgs: %empty { $$ = std::vector(); } + +imports: %empty { ; } + | imports0 { $$ = std::move($1); } + ; + +imports0: import { $$.push_back($1); } + | imports0 import { $1.push_back($2); $$ = std::move($1); } + ; + +import: IMPORT moduleName ";" { $$ = new ast::Import($2); } + ; + +moduleName: identifier { $$ = $1; } + | moduleName "." identifier { $$ = $1 + $2 + $3; } + ; + + +topLevelStmts: topLevelStmt { $$.push_back($1); } + | topLevelStmts topLevelStmt { $1.push_back($2); $$ = std::move($1); } + ; + +topLevelStmt: fnDecl { $$ = $1; } + | extFnDecl { $$ = $1; } + | valDecl { $$ = $1; } + ; + +blockStmts: blockStmt { $$.push_back($1); } + | blockStmts blockStmt { $1.push_back($2); $$ = std::move($1); } + ; + +blockStmt: valDecl { $$ = $1; } + | fnDecl { $$ = $1; } + | expr ";" { $$ = new ast::ExprStmt($1); } + ; + +valDecl: VAL identifier "=" expr ";" { $$ = new ast::ValDecl($2, nullptr, $4); } + | VAL identifier type "=" expr ";" { $$ = new ast::ValDecl($2, $3, $5); } + ; + +fnDecl: FN identifier "[" fnArgs "]" type "=" expr ";" { $$ = new ast::FnDecl($2, $4, $6, $8); } + ; + +extFnDecl: DECLARE FN identifier "[" fnArgs "]" type ";" { $$ = new ast::FnDecl($3, $5, $7, nullptr); } + ; + +fnArgs: %empty { ; } | fnArgs0 { $$ = std::move($1); } ; -fnArgs0: fnArg { $$ = std::vector(); $$.push_back($1); } +fnArgs0: fnArg { $$.push_back($1); } | fnArgs0 "," fnArg { $$.push_back($3); $$ = std::move($1); } ; -fnArg: identifier type { $$ = FnArg($1, $2); } +fnArg: identifier type { $$ = ast::FnArg($1, $2); } ; -type: type0 +types: type { $$.push_back($1); } + | types "," type { $1.push_back($3); $$ = std::move($1); } + ; + +type: identifier { $$ = new ast::NamedType($1); } + | "(" type ")" { $$ = $2; } + | "(" tupleTypes ")" { $$ = new ast::TupleType($2); } + | "[" fnTypeArgs "]" "->" type { $$ = new ast::FunctionType($2, $5); } ; -type0: identifier { $$ = new NamedType($1); } - | "(" type ")" { $$ = $2; } - ; +tupleTypes: type "," type { $$.push_back($1); $$.push_back($3); } + | tupleTypes "," type { $1.push_back($3); $$ = std::move($1); } + ; -exprs: expr { $$ = std::vector(); $$.push_back($1); } +fnTypeArgs: %empty { ; } + | types { $$ = std::move($1); } + ; + +exprs: expr { $$.push_back($1); } | exprs "," expr { $1.push_back($3); $$ = std::move($1); } ; @@ -150,54 +211,55 @@ expr: expr3 { $$ = $1; } expr3: expr2 { $$ = $1; } | "[" lambdaArgs "]" "->" expr { $$ = NULL; } + | "{" blockStmts "}" { $$ = new ast::BlockExpr($2); } ; expr2: expr1 { $$ = $1; } - | expr2 operator expr1 { $$ = new BinExpr($1, $2, $3); } + | expr2 operator expr1 { $$ = new ast::BinExpr($1, $2, $3); } ; expr1: expr0 { $$ = $1; } - | operator expr1 { $$ = new UnaryExpr($1, $2); } + | operator expr1 { $$ = new ast::UnaryExpr($1, $2); } ; expr0: literal { $$ = $1; } - | identifier { $$ = new Identifier($1); } - | expr0 "[" args "]" { $$ = new CallExpr($1, $3); } - | "(" expr ")" { $$ = new PrefExpr($2); } + | identifier { $$ = new ast::Identifier($1); } + | expr0 "[" args "]" { $$ = new ast::CallExpr($1, $3); } + | "(" expr ")" { $$ = new ast::PrefExpr($2); } ; -lambdaArgs: %empty { $$ = std::vector(); } +lambdaArgs: %empty { ; } | identifiers { $$ = std::move($1); } ; -args: %empty { $$ = std::vector(); } +args: %empty { ; } | exprs { $$ = std::move($1); } ; -literal: INT { $$ = new IntValue($1); } - | FLOAT { $$ = new FloatValue($1); } +literal: INT { $$ = new ast::IntValue($1); } + | FLOAT { $$ = new ast::FloatValue($1); } ; -operator: "->" { $$ = $1; } - | "=" { $$ = $1; } - | OPERATOR { $$ = $1; } +operator: "->" + | "=" + | OPERATOR ; -identifiers: identifier { $$ = std::vector(); $$.push_back($1); } +identifiers: identifier { $$.push_back($1); } | identifiers "," identifier { $1.push_back($3); $$ = std::move($1); } ; -identifier: keyword { $$ = $1; } - | IDENTIFIER { $$ = $1; } +identifier: keyword + | IDENTIFIER ; -keyword: FN { $$ = $1; } - | VAL { $$ = $1; } - | UNOP { $$ = $1; } - | BINOP { $$ = $1; } - | IMPORT { $$ = $1; } - | DECLARE { $$ = $1; } +keyword: FN + | VAL + | UNOP + | BINOP + | IMPORT + | DECLARE ; %% diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp index df22ac9..e2ede87 100644 --- a/compiler/src/main.cpp +++ b/compiler/src/main.cpp @@ -25,6 +25,6 @@ int main(int argc, char *argv[]) auto parser = ParserDriver(); parser.parse(buf.str()); - auto fn = (FnDecl *)parser.module->stmts.at(0); + auto fn = (ast::FnDecl *)parser.module->stmts.at(0); std::cout << fn->name << std::endl; } diff --git a/examples/42.plsm b/examples/42.plsm index 92eb877..1c55ef4 100644 --- a/examples/42.plsm +++ b/examples/42.plsm @@ -1 +1,9 @@ +import test.test; + fn main[] Int = 42; + +fn test[b Int] Int = { + fn helper[] Int = 10; + 20 * b; +}; + diff --git a/examples/stdlib.plsm b/examples/stdlib.plsm index ac6e258..a6354c0 100644 --- a/examples/stdlib.plsm +++ b/examples/stdlib.plsm @@ -1,29 +1,33 @@ -type Bool = class { +type Bool = { declare unop ! Bool; - declare binop &&(b Bool) Bool; - declare binop ||(b Bool) Bool; + declare binop &&[b Bool] Bool; + declare binop ||[b Bool] Bool; }; -type Int = class { +type Int = { declare unop + Int; declare unop - Int; - declare binop ==(Int) Bool; - declare binop !=(Int) Bool; - declare binop >(Int) Bool; - declare binop <(Int) Bool; - declare binop >=(Int) Bool; - declare binop <=(Int) Bool; + declare binop ==[Int] Bool; + declare binop !=[Int] Bool; + declare binop >[Int] Bool; + declare binop <[Int] Bool; + declare binop >=[Int] Bool; + declare binop <=[Int] Bool; - declare binop +(Int) Int; - declare binop -(Int) Int; - declare binop *(Int) Int; - declare binop /(Int) Int; - declare binop %(Int) Int; + declare binop +[Int] Int; + declare binop -[Int] Int; + declare binop *[Int] Int; + declare binop /[Int] Int; + declare binop %[Int] Int; - declare factory (f Float); - declare factory (); + declare factory [f Float]; + declare factory []; - declare fn str() String; + declare fn str[] String; +}; + +trait List{T} = { + fn };