diff --git a/generator.v b/generator.v index 5e78dc0..7d28ac7 100644 --- a/generator.v +++ b/generator.v @@ -24,6 +24,7 @@ fn mangle_struct(name string) string { fn get_type_format(type string) string { + dump(type) return match type { 'int', 'bool' {'d'} 'real' {'f'} @@ -46,7 +47,7 @@ fn (mut g Generator) get_c_type(typ string) string { return match typ { 'real' {'float'} 'int' {'int32_t'} - 'string' {'char*'} + 'string' {'OneString'} else {typ} } } @@ -70,12 +71,16 @@ fn (mut g Generator) gen_class_print_func(stmt ClassDecl) { g.out.writeln('for(int i=0; i') g.out.writeln('#include ') g.out.writeln('#include ') - //g.out.writeln('typedef struct __one_string_builtin__ {\nchar* string;\nint len;\n} string;') + g.out.writeln('typedef struct {\nchar* string;\nint len;\n} OneString;') for stmt in program { g.gen_stmt(stmt) } diff --git a/lexer.v b/lexer.v index 944ec05..a8133f8 100644 --- a/lexer.v +++ b/lexer.v @@ -5,6 +5,7 @@ import term enum TokenType as u8 { kw_let kw_const + kw_immutable type kw_if kw_else @@ -108,6 +109,7 @@ fn toktype_from_kw(kw string) TokenType { 'true', 'false' {.boolean} 'print' {.kw_print} 'class' {.kw_class} + 'immutable' {.kw_immutable} else {.unknown} } } @@ -127,7 +129,7 @@ fn is_real(str string) bool { fn is_keyword(str string) bool { return [ - "void", "int", "real", "bool", "string", "if", "else", "elif", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "class" + "void", "int", "real", "bool", "string", "if", "else", "elif", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "class", "immutable" ].contains(str) } diff --git a/one b/one index 775aea3..bc63d64 100755 Binary files a/one and b/one differ diff --git a/parser.v b/parser.v index 505d322..87fd000 100644 --- a/parser.v +++ b/parser.v @@ -32,6 +32,7 @@ type SymbolInfo = VarSymbolInfo | FuncSymbolInfo | ClassSymbolInfo struct VarSymbolInfo { type string + is_immutable bool } struct FuncSymbolInfo { @@ -96,7 +97,10 @@ fn (mut s SymbolTable) lookup_func(name string) ?FuncSymbolInfo { fn (mut s SymbolTable) define_class(name string, members []ClassMember) { mut members_info := map[string]VarSymbolInfo{} for member in members { - members_info[member.name] = VarSymbolInfo{member.type} + members_info[member.name] = VarSymbolInfo{ + type: member.type, + is_immutable: member.is_immutable + } } s.structs[name] = ClassSymbolInfo{name: name, members_info: members_info} } @@ -157,11 +161,13 @@ struct TypeExpr { struct ClassMember { name string type string + is_immutable bool } struct MemberAccess { from Expr member string + member_type string } struct ClassInstantiation { @@ -349,10 +355,6 @@ fn (mut p Parser) parse_ident(ident string) Expr { } } - if p.inside_struct { - return p.parse_class_member(ident) - } - return match p.peek().type { .increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}} .lparen {p.parse_call(ident)} @@ -363,25 +365,34 @@ fn (mut p Parser) parse_ident(ident string) Expr { fn (mut p Parser) parse_member_access(from Expr) MemberAccess { member_tok := p.next() if member_tok.type != .identifier {parse_error("Expected identifier after member access")} - return MemberAccess {from: from, member: member_tok.text} + from_class := p.symbols.lookup_class(p.get_expr_type(from)) or {panic("Accessing member from non-class type")} + if !(member_tok.text in from_class.members_info) {panic("Accessing undefined member ${member_tok.text}")} + member_type := from_class.members_info[member_tok.text].type + return MemberAccess {from: from, member: member_tok.text, member_type: member_type} } -fn (mut p Parser) parse_class_member(name string) ClassMember { +fn (mut p Parser) parse_class_member() ClassMember { + mut is_immut := false + if p.peek().type == .kw_immutable { + is_immut = true + p.next() + } + member_name := p.peek().text p.expect(.identifier) type_tok := p.peek() type_name := match type_tok.type { .type {type_tok.text} .identifier { - p.expect_ident_is_class(type_tok.text) - type_tok.text - } - else{parse_error("Expected type after class member ${name} in declaration, got ${p.peek().type}")} + p.expect_ident_is_class(type_tok.text) + type_tok.text + } + else{parse_error("Expected type after class member ${member_name} in declaration, got ${p.peek().type}")} } p.next() p.expect(.semicolon) - return ClassMember{name: name, type: type_name} + return ClassMember{name: member_name, type: type_name is_immutable: is_immut} } fn (mut p Parser) parse_class_inst(name string) ClassInstantiation { @@ -439,6 +450,20 @@ fn (mut p Parser) parse_print() PrintExpr { } fn (mut p Parser) parse_binary(left Expr, op string, prec Precedence) BinaryExpr { + + if op in ['=', '+=', '-=', '*=', '/='] { + if left is MemberAccess { + from_type := p.get_expr_type(left.from) + if class_info := p.symbols.lookup_class(from_type) { + if member_info := class_info.members_info[left.member] { + if member_info.is_immutable { + parse_error("Cannot assign to immutable member ${left.member} in class ${from_type}") + } + } + } + } + } + right := p.parse_expr(prec) binary_expr := BinaryExpr{left, op, right} @@ -513,13 +538,7 @@ fn (mut p Parser) get_expr_type(expr Expr) string { fninfo.type } MemberAccess { - mut type_from := p.get_expr_type(expr.from) - classinfo := p.symbols.lookup_class(type_from)or{parse_error("Non-existant class ${type_from}")} - if expr.member in classinfo.members_info { - classinfo.members_info[expr.member].type - } else { - parse_error("Undefined class member ${expr.member}") - } + expr.member_type } ClassInstantiation {expr.name} else {"Tried getting type of unexpected Expr"} @@ -695,8 +714,8 @@ fn (mut p Parser) parse_class() ClassDecl { p.expect(.identifier) p.expect(.lbracket) mut members := []ClassMember{} - for p.peek().type == .identifier { - members << p.parse_class_member(p.peek().text) + for p.peek().type != .rbracket { + members << p.parse_class_member() } p.expect(.rbracket) p.symbols.define_class(name, members) @@ -793,6 +812,10 @@ fn (mut p Parser) parse_block(no_scope bool) Block { } fn (mut p Parser) parse_program() ([]Stmt, SymbolTable) { + p.symbols.define_class('string',[ + ClassMember{'len', 'int', true} + ]) + p.symbols.variable_scopes << map[string]VarSymbolInfo{} for p.peek().type != .eof { p.statements << p.parse_statement()