structs
This commit is contained in:
58
generator.v
58
generator.v
@@ -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')
|
||||||
|
|||||||
4
lexer.v
4
lexer.v
@@ -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
2
main.v
@@ -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')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
123
parser.v
123
parser.v
@@ -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{}
|
||||||
@@ -280,11 +354,11 @@ fn (mut p Parser) parse_call(name string) FnCall {
|
|||||||
if p.peek().type != .rparen {
|
if p.peek().type != .rparen {
|
||||||
for {
|
for {
|
||||||
args << p.parse_expr(.lowest)
|
args << p.parse_expr(.lowest)
|
||||||
if p.peek().type == .comma {
|
if p.peek().type == .comma {
|
||||||
p.next()
|
p.next()
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expect(.rparen)
|
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 := 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,8 +495,15 @@ 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 {
|
||||||
parse_error("Expected variable type after name when declaring ${name_tok.text}")
|
.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)
|
p.expect(.equals)
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user