diff --git a/generator.v b/generator.v index 4ace1b0..4ef2b7f 100644 --- a/generator.v +++ b/generator.v @@ -9,7 +9,21 @@ mut: } fn mangle_var(name string) string { - return 'v${name}' + return 'one_v${name}' +} + +fn mangle_func(name string) string { + if name == 'main' {return 'main'} + return 'one_f${name}' +} + +fn mangle_struct(name string) string { + return 'one_s${name}_' +} + +fn mangle_if_struct_type(name string) string { + if name[0..6] != 'struct' {return name} + return 'struct ${mangle_struct(name[7..])}' } fn (mut g Generator) get_c_type(typ string) string { @@ -23,7 +37,7 @@ fn (mut g Generator) get_c_type(typ string) string { fn (mut g Generator) gen_stmt(stmt Stmt) { match stmt { VarDecl { - c_type := g.get_c_type(stmt.type) + c_type := mangle_if_struct_type(g.get_c_type(stmt.type)) if stmt.const { g.out.write_string('const ') } @@ -49,7 +63,7 @@ fn (mut g Generator) gen_stmt(stmt Stmt) { } FuncDecl { c_type := g.get_c_type(stmt.ret_type) - g.out.write_string('${c_type} ${stmt.name}(') + g.out.write_string('${c_type} ${mangle_func(stmt.name)}(') for param in stmt.params { g.gen_stmt(param) if param != stmt.params[stmt.params.len-1]{ @@ -63,6 +77,14 @@ fn (mut g Generator) gen_stmt(stmt Stmt) { c_type := g.get_c_type(stmt.type) g.out.write_string('${c_type} ${mangle_var(stmt.name)}') } + StructDecl { + g.out.writeln('struct ${mangle_struct(stmt.name)} {') + for member in stmt.members { + g.gen_expr(member) + g.out.writeln(';') + } + g.out.writeln('};') + } } } @@ -113,7 +135,7 @@ fn (mut g Generator) gen_expr(expr Expr) { g.out.write_string(')') } FnCall { - g.out.write_string('${expr.name}(') + g.out.write_string('${mangle_func(expr.name)}(') for arg in expr.args { g.gen_expr(arg) if arg != expr.args[expr.args.len-1]{ @@ -122,6 +144,20 @@ fn (mut g Generator) gen_expr(expr Expr) { } g.out.write_string(')') } + StructMember { + c_type := g.get_c_type(expr.type) + g.out.write_string('${c_type} ${expr.name}') + } + StructInstantiation { + g.out.write_string('(struct ${mangle_struct(expr.name)}){') + for m_expr in expr.member_values { + g.gen_expr(m_expr) + if m_expr != expr.member_values[expr.member_values.len - 1] { + g.out.write_string(', ') + } + } + g.out.write_string('}') + } else {panic("Unimplemented expression")} } } @@ -138,21 +174,25 @@ fn (mut g Generator) gen_c(program []Stmt) string { } -fn compile_with_clang(c_code string, output_name string, keep_c bool) { +fn compile(c_code string, output_name string, keep_c bool, compiler string) { c_file := 'middle_c.c' os.write_file(c_file, c_code) or { eprintln('Failed to write C file: $err') return } - clang_cmd := 'clang ${c_file} -o ${output_name} -O2' + cmd := match compiler { + 'clang' {'clang ${c_file} -o ${output_name} -O2'} + 'gcc' {'gcc ${c_file} -o ${output_name} -O2'} + else {panic("Invalid compiler")} + } - println('Executing: ${clang_cmd}') + println('Executing: ${cmd}') - result := os.execute(clang_cmd) + result := os.execute(cmd) if result.exit_code != 0 { - eprintln('Clang Compilation Failed:') + eprintln('${compiler} Compilation Failed:') eprintln(result.output) } else { println('Compilation successful! Binary created: $output_name') diff --git a/lexer.v b/lexer.v index 46e2936..a6edacc 100644 --- a/lexer.v +++ b/lexer.v @@ -13,6 +13,7 @@ enum TokenType as u8 { kw_fn kw_return kw_print + kw_struct integer real boolean @@ -103,6 +104,7 @@ fn toktype_from_kw(kw string) TokenType { 'return' {.kw_return} 'true', 'false' {.boolean} 'print' {.kw_print} + 'struct' {.kw_struct} else {.unknown} } } @@ -118,7 +120,7 @@ fn is_real(str string) bool { fn is_keyword(str string) bool { return [ - "void", "int", "real", "bool", "if", "else", "for", "break", "fn", "return", "let", "const", "true", "false", "print" + "void", "int", "real", "bool", "if", "else", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "struct" ].contains(str) } diff --git a/main.v b/main.v index 4cd1079..cd1e5c4 100644 --- a/main.v +++ b/main.v @@ -31,6 +31,6 @@ fn main() { out_c := generator.gen_c(statements) - compile_with_clang(out_c, 'exec', true) + compile(out_c, 'exec', true, 'gcc') } diff --git a/one b/one index a9d875d..da46539 100755 Binary files a/one and b/one differ diff --git a/parser.v b/parser.v index cbcb340..8ad03df 100644 --- a/parser.v +++ b/parser.v @@ -26,7 +26,7 @@ fn (p Parser) get_precedence(tok_type TokenType) Precedence { // ------------------------------------------- Symbol Table -type SymbolInfo = VarSymbolInfo | FuncSymbolInfo +type SymbolInfo = VarSymbolInfo | FuncSymbolInfo | StructTypeSymbolInfo struct VarSymbolInfo { type string @@ -37,10 +37,15 @@ struct FuncSymbolInfo { block Block } +struct StructTypeSymbolInfo { + name string +} + struct SymbolTable { mut: variable_scopes []map[string]VarSymbolInfo functions map[string]FuncSymbolInfo + structs map[string]StructTypeSymbolInfo } fn (mut s SymbolTable) define_var(name string, typ string) { @@ -85,13 +90,25 @@ fn (mut s SymbolTable) lookup_func(name string) ?FuncSymbolInfo { return none } +fn (mut s SymbolTable) define_struct_type(name string) { + s.structs[name] = StructTypeSymbolInfo{name: name} +} + +fn (mut s SymbolTable) lookup_struct_type(name string) ?StructTypeSymbolInfo { + if name in s.structs { + return s.structs[name] + } + return none +} + fn (mut s SymbolTable) is_in_global_scope() bool { return s.variable_scopes.len == 1 } + // ------------------------------------------- Expressions -type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall +type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | StructMember | StructInstantiation struct VoidExpr {} @@ -126,6 +143,16 @@ struct TypeExpr { name string } +struct StructMember { + name string + type string +} + +struct StructInstantiation { + name string + member_values []Expr +} + struct Function { name string } @@ -151,7 +178,7 @@ struct FnCall { // ------------------------------------------- Statements -type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | FuncDecl | Param +type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | FuncDecl | Param | StructDecl struct VarDecl { name string @@ -167,6 +194,11 @@ struct FuncDecl { block Block } +struct StructDecl { + name string + members []StructMember +} + struct ExprStmt { expr Expr } @@ -193,6 +225,7 @@ mut: pos int line int statements []Stmt + inside_struct bool } fn (mut p Parser) peek() Token { @@ -266,6 +299,17 @@ fn (mut p Parser) parse_expr(prec Precedence) Expr { } fn (mut p Parser) parse_ident(ident string) Expr { + if p.symbols.lookup_struct_type(ident) != none { + return match p.peek().type { + .lbracket {p.parse_struct_inst(ident)} + else {p.parse_type('struct ${ident}')} + } + } + + if p.inside_struct { + return p.parse_struct_member(ident) + } + return match p.peek().type { .increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}} .lparen {p.parse_call(ident)} @@ -273,6 +317,36 @@ fn (mut p Parser) parse_ident(ident string) Expr { } } +fn (mut p Parser) parse_struct_member(name string) StructMember { + p.expect(.identifier) + if p.peek().type != .type { + dump(p.peek()) + parse_error("Expected type after struct member ${name} in declaration, got ${p.peek().type}") + } + type := p.peek().text + p.expect(.type) + p.expect(.semicolon) + return StructMember{name: name, type: type} +} + +fn (mut p Parser) parse_struct_inst(name string) StructInstantiation { + p.expect(.lbracket) + mut member_values := []Expr{} + + if p.peek().type != .rbracket { + for { + member_values << p.parse_expr(.lowest) + if p.peek().type == .comma { + p.next() + } else { + break + } + } + } + p.expect(.rbracket) + return StructInstantiation{name: name, member_values: member_values} +} + fn (mut p Parser) parse_call(name string) FnCall { p.expect(.lparen) mut args := []Expr{} @@ -280,11 +354,11 @@ fn (mut p Parser) parse_call(name string) FnCall { if p.peek().type != .rparen { for { args << p.parse_expr(.lowest) - if p.peek().type == .comma { - p.next() - } else { - break - } + if p.peek().type == .comma { + p.next() + } else { + break + } } } p.expect(.rparen) @@ -369,10 +443,9 @@ fn (mut p Parser) get_expr_type(expr Expr) string { fninfo := p.symbols.lookup_func(expr.name) or {parse_error("Tried to call undefined function ${expr.name}")} fninfo.type } + StructInstantiation {expr.name} else {"Tried getting type of unexpected Expr"} } - - } fn (mut p Parser) is_op_valid_for_type(type string, op string) bool { @@ -408,12 +481,11 @@ fn (mut p Parser) parse_statement() Stmt { .kw_return {return p.parse_return_stmt()} .kw_fn {return p.parse_func_decl()} .lbracket {return p.parse_block(false)} + .kw_struct {return p.parse_struct()} else {return p.parse_expr_stmt()} } } - - fn (mut p Parser) parse_var_decl(is_const bool) VarDecl { p.next() @@ -423,8 +495,15 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl { } type_tok := p.next() - if type_tok.type != .type { - parse_error("Expected variable type after name when declaring ${name_tok.text}") + type_name := match type_tok.type { + .type {type_tok.text} + .identifier { + if p.symbols.lookup_struct_type(type_tok.text) == none { + parse_error("Expected variable type after name when declaring ${name_tok.text}") + } + 'struct ${type_tok.text}' + } + else{parse_error("Expected variable type after name when declaring ${name_tok.text}")} } p.expect(.equals) @@ -443,7 +522,7 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl { return VarDecl { name: name_tok.text value: val - type: type_tok.text + type: type_name const: is_const } } @@ -514,6 +593,20 @@ fn (mut p Parser) parse_func_decl() FuncDecl { } } +fn (mut p Parser) parse_struct() StructDecl { + p.expect(.kw_struct) + name := p.peek().text + p.expect(.identifier) + p.expect(.lbracket) + mut members := []StructMember{} + for p.peek().type == .identifier { + members << p.parse_struct_member(p.peek().text) + } + p.expect(.rbracket) + p.symbols.define_struct_type(name) + return StructDecl{name: name, members: members} +} + fn (mut p Parser) parse_return_stmt() ReturnStmt { p.expect(.kw_return)