This commit is contained in:
uan
2026-02-05 13:18:40 +01:00
parent 12c925ebcd
commit 0d5cc35b5a
5 changed files with 161 additions and 26 deletions

View File

@@ -9,7 +9,21 @@ mut:
} }
fn mangle_var(name string) string { 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 { 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) { fn (mut g Generator) gen_stmt(stmt Stmt) {
match stmt { match stmt {
VarDecl { VarDecl {
c_type := g.get_c_type(stmt.type) c_type := mangle_if_struct_type(g.get_c_type(stmt.type))
if stmt.const { if stmt.const {
g.out.write_string('const ') g.out.write_string('const ')
} }
@@ -49,7 +63,7 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
} }
FuncDecl { FuncDecl {
c_type := g.get_c_type(stmt.ret_type) 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 { for param in stmt.params {
g.gen_stmt(param) g.gen_stmt(param)
if param != stmt.params[stmt.params.len-1]{ 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) c_type := g.get_c_type(stmt.type)
g.out.write_string('${c_type} ${mangle_var(stmt.name)}') 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(')') g.out.write_string(')')
} }
FnCall { FnCall {
g.out.write_string('${expr.name}(') g.out.write_string('${mangle_func(expr.name)}(')
for arg in expr.args { for arg in expr.args {
g.gen_expr(arg) g.gen_expr(arg)
if arg != expr.args[expr.args.len-1]{ if arg != expr.args[expr.args.len-1]{
@@ -122,6 +144,20 @@ fn (mut g Generator) gen_expr(expr Expr) {
} }
g.out.write_string(')') 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")} 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' c_file := 'middle_c.c'
os.write_file(c_file, c_code) or { os.write_file(c_file, c_code) or {
eprintln('Failed to write C file: $err') eprintln('Failed to write C file: $err')
return 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 { if result.exit_code != 0 {
eprintln('Clang Compilation Failed:') eprintln('${compiler} Compilation Failed:')
eprintln(result.output) eprintln(result.output)
} else { } else {
println('Compilation successful! Binary created: $output_name') println('Compilation successful! Binary created: $output_name')

View File

@@ -13,6 +13,7 @@ enum TokenType as u8 {
kw_fn kw_fn
kw_return kw_return
kw_print kw_print
kw_struct
integer integer
real real
boolean boolean
@@ -103,6 +104,7 @@ fn toktype_from_kw(kw string) TokenType {
'return' {.kw_return} 'return' {.kw_return}
'true', 'false' {.boolean} 'true', 'false' {.boolean}
'print' {.kw_print} 'print' {.kw_print}
'struct' {.kw_struct}
else {.unknown} else {.unknown}
} }
} }
@@ -118,7 +120,7 @@ fn is_real(str string) bool {
fn is_keyword(str string) bool { fn is_keyword(str string) bool {
return [ 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) ].contains(str)
} }

2
main.v
View File

@@ -31,6 +31,6 @@ fn main() {
out_c := generator.gen_c(statements) out_c := generator.gen_c(statements)
compile_with_clang(out_c, 'exec', true) compile(out_c, 'exec', true, 'gcc')
} }

BIN
one

Binary file not shown.

111
parser.v
View File

@@ -26,7 +26,7 @@ fn (p Parser) get_precedence(tok_type TokenType) Precedence {
// ------------------------------------------- Symbol Table // ------------------------------------------- Symbol Table
type SymbolInfo = VarSymbolInfo | FuncSymbolInfo type SymbolInfo = VarSymbolInfo | FuncSymbolInfo | StructTypeSymbolInfo
struct VarSymbolInfo { struct VarSymbolInfo {
type string type string
@@ -37,10 +37,15 @@ struct FuncSymbolInfo {
block Block block Block
} }
struct StructTypeSymbolInfo {
name string
}
struct SymbolTable { struct SymbolTable {
mut: mut:
variable_scopes []map[string]VarSymbolInfo variable_scopes []map[string]VarSymbolInfo
functions map[string]FuncSymbolInfo functions map[string]FuncSymbolInfo
structs map[string]StructTypeSymbolInfo
} }
fn (mut s SymbolTable) define_var(name string, typ string) { 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 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 { fn (mut s SymbolTable) is_in_global_scope() bool {
return s.variable_scopes.len == 1 return s.variable_scopes.len == 1
} }
// ------------------------------------------- Expressions // ------------------------------------------- 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 {} struct VoidExpr {}
@@ -126,6 +143,16 @@ struct TypeExpr {
name string name string
} }
struct StructMember {
name string
type string
}
struct StructInstantiation {
name string
member_values []Expr
}
struct Function { struct Function {
name string name string
} }
@@ -151,7 +178,7 @@ struct FnCall {
// ------------------------------------------- Statements // ------------------------------------------- Statements
type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | FuncDecl | Param type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | FuncDecl | Param | StructDecl
struct VarDecl { struct VarDecl {
name string name string
@@ -167,6 +194,11 @@ struct FuncDecl {
block Block block Block
} }
struct StructDecl {
name string
members []StructMember
}
struct ExprStmt { struct ExprStmt {
expr Expr expr Expr
} }
@@ -193,6 +225,7 @@ mut:
pos int pos int
line int line int
statements []Stmt statements []Stmt
inside_struct bool
} }
fn (mut p Parser) peek() Token { 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 { 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 { return match p.peek().type {
.increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}} .increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}}
.lparen {p.parse_call(ident)} .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 { fn (mut p Parser) parse_call(name string) FnCall {
p.expect(.lparen) p.expect(.lparen)
mut args := []Expr{} mut args := []Expr{}
@@ -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 := p.symbols.lookup_func(expr.name) or {parse_error("Tried to call undefined function ${expr.name}")}
fninfo.type fninfo.type
} }
StructInstantiation {expr.name}
else {"Tried getting type of unexpected Expr"} else {"Tried getting type of unexpected Expr"}
} }
} }
fn (mut p Parser) is_op_valid_for_type(type string, op string) bool { 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_return {return p.parse_return_stmt()}
.kw_fn {return p.parse_func_decl()} .kw_fn {return p.parse_func_decl()}
.lbracket {return p.parse_block(false)} .lbracket {return p.parse_block(false)}
.kw_struct {return p.parse_struct()}
else {return p.parse_expr_stmt()} else {return p.parse_expr_stmt()}
} }
} }
fn (mut p Parser) parse_var_decl(is_const bool) VarDecl { fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
p.next() p.next()
@@ -423,9 +495,16 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
} }
type_tok := p.next() type_tok := p.next()
if type_tok.type != .type { 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}") 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) p.expect(.equals)
val := p.parse_expr(.lowest) val := p.parse_expr(.lowest)
@@ -443,7 +522,7 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
return VarDecl { return VarDecl {
name: name_tok.text name: name_tok.text
value: val value: val
type: type_tok.text type: type_name
const: is_const 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 { fn (mut p Parser) parse_return_stmt() ReturnStmt {
p.expect(.kw_return) p.expect(.kw_return)