SelectorExpr; receivers; struct field check; if expression
parent
3c65af8b9a
commit
492dfebd15
2
v2.v
2
v2.v
|
@ -22,7 +22,7 @@ fn main() {
|
||||||
println('V2 $path')
|
println('V2 $path')
|
||||||
table := table.new_table()
|
table := table.new_table()
|
||||||
program := parser.parse_file(path, table)
|
program := parser.parse_file(path, table)
|
||||||
res := gen.cgen([program])
|
res := gen.cgen([program], table)
|
||||||
mut out := os.create('out.c')?
|
mut out := os.create('out.c')?
|
||||||
out.writeln(cdefs)
|
out.writeln(cdefs)
|
||||||
out.writeln(res)
|
out.writeln(res)
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub:
|
||||||
element_size int
|
element_size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private function, used by V (`nums := []int`)
|
// Internal function, used by V (`nums := []int`)
|
||||||
fn new_array(mylen int, cap int, elm_size int) array {
|
fn new_array(mylen int, cap int, elm_size int) array {
|
||||||
cap_ := if cap == 0 { 1 } else { cap }
|
cap_ := if cap == 0 { 1 } else { cap }
|
||||||
arr := array{
|
arr := array{
|
||||||
|
@ -28,7 +28,7 @@ fn new_array(mylen int, cap int, elm_size int) array {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
pub fn make(len, cap, elm_size int) array {
|
pub fn make(len int, cap int, elm_size int) array {
|
||||||
return new_array(len, cap, elm_size)
|
return new_array(len, cap, elm_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,9 @@ fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array {
|
||||||
data: calloc(cap_ * elm_size)
|
data: calloc(cap_ * elm_size)
|
||||||
}
|
}
|
||||||
// TODO Write all memory functions (like memcpy) in V
|
// TODO Write all memory functions (like memcpy) in V
|
||||||
C.memcpy(arr.data, c_array, len * elm_size)
|
C.memcpy(
|
||||||
|
arr.data,
|
||||||
|
c_array, len * elm_size)
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
v.table
|
v.table
|
||||||
v.parser
|
v.parser
|
||||||
v.gen
|
v.gen
|
||||||
|
time
|
||||||
)
|
)
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
|
@ -397,7 +398,7 @@ pub fn (v mut V) compile2() {
|
||||||
}
|
}
|
||||||
table := table.new_table()
|
table := table.new_table()
|
||||||
files := parser.parse_files(v.files, table)
|
files := parser.parse_files(v.files, table)
|
||||||
c := gen.cgen(files)
|
c := gen.cgen(files, table)
|
||||||
println('out: $v.out_name_c')
|
println('out: $v.out_name_c')
|
||||||
os.write_file(v.out_name_c, c)
|
os.write_file(v.out_name_c, c)
|
||||||
/*
|
/*
|
||||||
|
@ -423,9 +424,12 @@ pub fn (v mut V) compile_x64() {
|
||||||
//v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare'))
|
//v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare'))
|
||||||
v.files << v.dir
|
v.files << v.dir
|
||||||
|
|
||||||
table := &table.Table{}
|
table := &table.new_table()
|
||||||
|
ticks := time.ticks()
|
||||||
files := parser.parse_files(v.files, table)
|
files := parser.parse_files(v.files, table)
|
||||||
|
println('PARSE: ${time.ticks() - ticks}ms')
|
||||||
x64.gen(files, v.out_name)
|
x64.gen(files, v.out_name)
|
||||||
|
println('x64 GEN: ${time.ticks() - ticks}ms')
|
||||||
/*
|
/*
|
||||||
for f in v.files {
|
for f in v.files {
|
||||||
v.parse(f, .decl)
|
v.parse(f, .decl)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral |
|
pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral |
|
||||||
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit
|
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr
|
||||||
|
|
||||||
pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt |
|
pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt |
|
||||||
ForStmt | StructDecl
|
ForStmt | StructDecl
|
||||||
|
@ -17,6 +17,7 @@ ForStmt | StructDecl
|
||||||
pub struct ExprStmt {
|
pub struct ExprStmt {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
expr Expr
|
||||||
|
typ types.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IntegerLiteral {
|
pub struct IntegerLiteral {
|
||||||
|
@ -40,6 +41,13 @@ pub:
|
||||||
val bool
|
val bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `foo.bar`
|
||||||
|
pub struct SelectorExpr {
|
||||||
|
pub:
|
||||||
|
expr Expr
|
||||||
|
field string
|
||||||
|
}
|
||||||
|
|
||||||
// module declaration
|
// module declaration
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub:
|
pub:
|
||||||
|
@ -88,6 +96,8 @@ pub:
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
typ types.Type
|
typ types.Type
|
||||||
args []Arg
|
args []Arg
|
||||||
|
is_pub bool
|
||||||
|
receiver Field
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CallExpr {
|
pub struct CallExpr {
|
||||||
|
@ -164,6 +174,8 @@ pub:
|
||||||
cond Expr
|
cond Expr
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
else_stmts []Stmt
|
else_stmts []Stmt
|
||||||
|
typ types.Type
|
||||||
|
left Expr // `a` in `a := if ...`
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ForStmt {
|
pub struct ForStmt {
|
||||||
|
|
|
@ -3,18 +3,22 @@ module gen
|
||||||
import (
|
import (
|
||||||
strings
|
strings
|
||||||
v.ast
|
v.ast
|
||||||
|
v.table
|
||||||
|
v.types
|
||||||
term
|
term
|
||||||
)
|
)
|
||||||
|
|
||||||
struct Gen {
|
struct Gen {
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
||||||
|
table &table.Table
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cgen(files []ast.File) string {
|
pub fn cgen(files []ast.File, table &table.Table) string {
|
||||||
mut g := Gen{
|
mut g := Gen{
|
||||||
out: strings.new_builder(100)
|
out: strings.new_builder(100)
|
||||||
definitions: strings.new_builder(100)
|
definitions: strings.new_builder(100)
|
||||||
|
table: table
|
||||||
}
|
}
|
||||||
for file in files {
|
for file in files {
|
||||||
for stmt in file.stmts {
|
for stmt in file.stmts {
|
||||||
|
@ -139,6 +143,9 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
ast.BinaryExpr {
|
ast.BinaryExpr {
|
||||||
g.expr(it.left)
|
g.expr(it.left)
|
||||||
|
if it.op == .dot {
|
||||||
|
println('!! dot')
|
||||||
|
}
|
||||||
g.write(' $it.op.str() ')
|
g.write(' $it.op.str() ')
|
||||||
g.expr(it.right)
|
g.expr(it.right)
|
||||||
// if typ.name != typ2.name {
|
// if typ.name != typ2.name {
|
||||||
|
@ -184,11 +191,28 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||||
g.write('false')
|
g.write('false')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast.SelectorExpr {
|
||||||
|
g.expr(it.expr)
|
||||||
|
g.write('.')
|
||||||
|
g.write(it.field)
|
||||||
|
}
|
||||||
ast.IfExpr {
|
ast.IfExpr {
|
||||||
|
// If expression? Assign the value to a temp var.
|
||||||
|
// Previously ?: was used, but it's too unreliable.
|
||||||
|
mut tmp := ''
|
||||||
|
if it.typ.idx != types.void_type.idx {
|
||||||
|
tmp = g.table.new_tmp_var()
|
||||||
|
// g.writeln('$it.typ.name $tmp;')
|
||||||
|
}
|
||||||
g.write('if (')
|
g.write('if (')
|
||||||
g.expr(it.cond)
|
g.expr(it.cond)
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
for stmt in it.stmts {
|
for i, stmt in it.stmts {
|
||||||
|
// Assign ret value
|
||||||
|
if i == it.stmts.len - 1 && it.typ.idx != types.void_type.idx {
|
||||||
|
// g.writeln('$tmp =')
|
||||||
|
println(1)
|
||||||
|
}
|
||||||
g.stmt(stmt)
|
g.stmt(stmt)
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
|
|
|
@ -23,13 +23,14 @@ fn test_c_files() {
|
||||||
}
|
}
|
||||||
table := &table.new_table()
|
table := &table.new_table()
|
||||||
program := parser.parse_file(path, table)
|
program := parser.parse_file(path, table)
|
||||||
res := gen.cgen([program])
|
res := gen.cgen([program], table)
|
||||||
if compare_texts(res, ctext) {
|
if compare_texts(res, ctext) {
|
||||||
eprintln('${i}... ' + term.green('OK'))
|
eprintln('${i}... ' + term.green('OK'))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
eprintln('${i}... ' + term.red('FAIL'))
|
eprintln('${i}... ' + term.red('FAIL'))
|
||||||
eprintln('expected:\n$ctext\ngot:\n$res')
|
eprintln(path)
|
||||||
|
eprintln('got:\n$res')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
void foo(int a);
|
void foo(int a);
|
||||||
|
int get_int(string a);
|
||||||
|
int get_int2();
|
||||||
|
void myuser();
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int age;
|
||||||
|
} User;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int a = 10;
|
int a = 10;
|
||||||
|
@ -10,5 +17,22 @@ return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void foo(int a) {
|
void foo(int a) {
|
||||||
|
void n = get_int2();
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_int(string a) {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_int2() {
|
||||||
|
string a = tos3("hello");
|
||||||
|
return get_int(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void myuser() {
|
||||||
|
User user = (User){
|
||||||
|
.age = 10,
|
||||||
|
};
|
||||||
|
User age = user.age;
|
||||||
|
bool b = age > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
struct User {
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
a := 10
|
a := 10
|
||||||
a++
|
a++
|
||||||
|
@ -7,5 +11,21 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(a int) {
|
fn foo(a int) {
|
||||||
|
n := get_int2()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_int(a string) int {
|
||||||
|
return 10
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_int2() int {
|
||||||
|
a := 'hello'
|
||||||
|
return get_int(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn myuser() {
|
||||||
|
user := User{age:10}
|
||||||
|
age := user.age
|
||||||
|
b := age > 0
|
||||||
|
//b2 := user.age > 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn foo() {
|
||||||
|
a := if true { 1 } else { 2 }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -20,7 +20,9 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
mut is_unknown := false
|
mut is_unknown := false
|
||||||
mut args := []ast.Expr
|
mut args := []ast.Expr
|
||||||
|
mut return_type := types.void_type
|
||||||
if f := p.table.find_fn(fn_name) {
|
if f := p.table.find_fn(fn_name) {
|
||||||
|
return_type = f.return_type
|
||||||
for i, arg in f.args {
|
for i, arg in f.args {
|
||||||
e,typ := p.expr(0)
|
e,typ := p.expr(0)
|
||||||
if !types.check(arg.typ, typ) {
|
if !types.check(arg.typ, typ) {
|
||||||
|
@ -51,16 +53,38 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
|
||||||
args: args
|
args: args
|
||||||
is_unknown: is_unknown
|
is_unknown: is_unknown
|
||||||
tok: tok
|
tok: tok
|
||||||
|
// typ: return_type
|
||||||
|
|
||||||
}
|
}
|
||||||
if is_unknown {
|
if is_unknown {
|
||||||
p.table.unknown_calls << node
|
p.table.unknown_calls << node
|
||||||
}
|
}
|
||||||
return node,types.int_type
|
return node,return_type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) fn_decl() ast.FnDecl {
|
fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||||
|
is_pub := p.tok.kind == .key_pub
|
||||||
|
if is_pub {
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
p.table.clear_vars()
|
p.table.clear_vars()
|
||||||
p.check(.key_fn)
|
p.check(.key_fn)
|
||||||
|
// Receiver?
|
||||||
|
mut rec_name := ''
|
||||||
|
mut rec_type := types.void_type
|
||||||
|
if p.tok.kind == .lpar {
|
||||||
|
p.next()
|
||||||
|
rec_name = p.check_name()
|
||||||
|
if p.tok.kind == .key_mut {
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
rec_type = p.parse_type()
|
||||||
|
p.table.register_var(table.Var{
|
||||||
|
name: rec_name
|
||||||
|
typ: rec_type
|
||||||
|
})
|
||||||
|
p.check(.rpar)
|
||||||
|
}
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
// println('fn decl $name')
|
// println('fn decl $name')
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
|
@ -68,8 +92,14 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||||
mut args := []table.Var
|
mut args := []table.Var
|
||||||
mut ast_args := []ast.Arg
|
mut ast_args := []ast.Arg
|
||||||
for p.tok.kind != .rpar {
|
for p.tok.kind != .rpar {
|
||||||
arg_name := p.check_name()
|
mut arg_names := [p.check_name()]
|
||||||
|
// `a, b, c int`
|
||||||
|
for p.tok.kind == .comma {
|
||||||
|
p.check(.comma)
|
||||||
|
arg_names << p.check_name()
|
||||||
|
}
|
||||||
typ := p.parse_type()
|
typ := p.parse_type()
|
||||||
|
for arg_name in arg_names {
|
||||||
arg := table.Var{
|
arg := table.Var{
|
||||||
name: arg_name
|
name: arg_name
|
||||||
typ: typ
|
typ: typ
|
||||||
|
@ -80,6 +110,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||||
typ: typ
|
typ: typ
|
||||||
name: arg_name
|
name: arg_name
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if p.tok.kind != .rpar {
|
if p.tok.kind != .rpar {
|
||||||
p.check(.comma)
|
p.check(.comma)
|
||||||
}
|
}
|
||||||
|
@ -94,6 +125,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||||
p.table.register_fn(table.Fn{
|
p.table.register_fn(table.Fn{
|
||||||
name: name
|
name: name
|
||||||
args: args
|
args: args
|
||||||
|
return_type: typ
|
||||||
})
|
})
|
||||||
stmts := p.parse_block()
|
stmts := p.parse_block()
|
||||||
return ast.FnDecl{
|
return ast.FnDecl{
|
||||||
|
@ -101,16 +133,23 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||||
stmts: stmts
|
stmts: stmts
|
||||||
typ: typ
|
typ: typ
|
||||||
args: ast_args
|
args: ast_args
|
||||||
|
is_pub: is_pub
|
||||||
|
receiver: ast.Field{
|
||||||
|
name: rec_name
|
||||||
|
typ: rec_type
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (p &Parser) check_fn_calls() {
|
pub fn (p &Parser) check_fn_calls() {
|
||||||
println('check fn calls')
|
println('check fn calls2')
|
||||||
for call in p.table.unknown_calls {
|
for call in p.table.unknown_calls {
|
||||||
f := p.table.find_fn(call.name) or {
|
f := p.table.find_fn(call.name) or {
|
||||||
p.error_at_line('unknown function `$call.name`', call.tok.line_nr)
|
p.error_at_line('unknown function `$call.name`', call.tok.line_nr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
println(f.name)
|
println(f.name)
|
||||||
|
// println(f.return_type.name)
|
||||||
|
// println('IN AST typ=' + call.typ.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ mut:
|
||||||
// vars []string
|
// vars []string
|
||||||
table &table.Table
|
table &table.Table
|
||||||
return_type types.Type
|
return_type types.Type
|
||||||
|
is_c bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
|
pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
|
||||||
|
@ -74,9 +75,11 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
|
||||||
|
|
||||||
// former get_type()
|
// former get_type()
|
||||||
pub fn (p mut Parser) parse_type() types.Type {
|
pub fn (p mut Parser) parse_type() types.Type {
|
||||||
typ := p.table.types[p.tok.lit]
|
typ := p.table.find_type(p.tok.lit) or {
|
||||||
if isnil(typ.name.str) || typ.name == '' {
|
// typ := p.table.types[p.tok.lit]
|
||||||
|
// if isnil(typ.name.str) || typ.name == '' {
|
||||||
p.error('undefined type `$p.tok.lit`')
|
p.error('undefined type `$p.tok.lit`')
|
||||||
|
exit(0)
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
return typ
|
return typ
|
||||||
|
@ -181,9 +184,10 @@ pub fn (p mut Parser) stmt() ast.Stmt {
|
||||||
return p.for_statement()
|
return p.for_statement()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
expr,_ := p.expr(0)
|
expr,typ := p.expr(0)
|
||||||
return ast.ExprStmt{
|
return ast.ExprStmt{
|
||||||
expr: expr
|
expr: expr
|
||||||
|
typ: typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,7 +246,12 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
if p.tok.lit == 'C' {
|
||||||
|
p.is_c = true
|
||||||
|
println('is c')
|
||||||
|
p.next()
|
||||||
|
p.check(.dot)
|
||||||
|
}
|
||||||
// fn call
|
// fn call
|
||||||
if p.peek_tok.kind == .lpar {
|
if p.peek_tok.kind == .lpar {
|
||||||
x,typ2 := p.call_expr() // TODO `node,typ :=` should work
|
x,typ2 := p.call_expr() // TODO `node,typ :=` should work
|
||||||
|
@ -330,6 +339,25 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
|
||||||
// left binding power
|
// left binding power
|
||||||
for rbp < p.tok.precedence() {
|
for rbp < p.tok.precedence() {
|
||||||
prev_tok := p.tok
|
prev_tok := p.tok
|
||||||
|
if prev_tok.kind == .dot {
|
||||||
|
p.warn('dot prev_tok = $prev_tok.str() typ=$typ.name')
|
||||||
|
p.next()
|
||||||
|
field := p.check_name()
|
||||||
|
mut ok := false
|
||||||
|
for f in typ.fields {
|
||||||
|
if f.name == field {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
p.error('unknown field `${typ.name}.$field`')
|
||||||
|
}
|
||||||
|
node = ast.SelectorExpr{
|
||||||
|
expr: node
|
||||||
|
field: field
|
||||||
|
}
|
||||||
|
return node,typ
|
||||||
|
}
|
||||||
p.next()
|
p.next()
|
||||||
mut t2 := types.Type{}
|
mut t2 := types.Type{}
|
||||||
// left denotation (infix / postfix)
|
// left denotation (infix / postfix)
|
||||||
|
@ -410,23 +438,36 @@ fn (p mut Parser) for_statement() ast.ForStmt {
|
||||||
fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
|
fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
|
||||||
mut node := ast.Expr{}
|
mut node := ast.Expr{}
|
||||||
p.check(.key_if)
|
p.check(.key_if)
|
||||||
cond,typ := p.expr(0)
|
cond,cond_type := p.expr(0)
|
||||||
if !types.check(types.bool_type, typ) {
|
if !types.check(types.bool_type, cond_type) {
|
||||||
p.error('non-bool used as if condition')
|
p.error('non-bool used as if condition')
|
||||||
}
|
}
|
||||||
stmts := p.parse_block()
|
stmts := p.parse_block()
|
||||||
mut else_stmts := []ast.Stmt
|
mut else_stmts := []ast.Stmt
|
||||||
if p.tok.kind == .key_else {
|
if p.tok.kind == .key_else {
|
||||||
println('GOT ELSE')
|
// println('GOT ELSE')
|
||||||
p.check(.key_else)
|
p.check(.key_else)
|
||||||
else_stmts = p.parse_block()
|
else_stmts = p.parse_block()
|
||||||
}
|
}
|
||||||
|
mut typ := types.void_type
|
||||||
|
// mut left := ast.Expr{}
|
||||||
|
match stmts[stmts.len - 1] {
|
||||||
|
ast.ExprStmt {
|
||||||
|
typ = it.typ
|
||||||
|
// return node,it.typ
|
||||||
|
// left =
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
node = ast.IfExpr{
|
node = ast.IfExpr{
|
||||||
cond: cond
|
cond: cond
|
||||||
stmts: stmts
|
stmts: stmts
|
||||||
else_stmts: else_stmts
|
else_stmts: else_stmts
|
||||||
|
typ: typ
|
||||||
|
// left: left
|
||||||
|
|
||||||
}
|
}
|
||||||
return node,types.void_type
|
return node,typ
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) {
|
fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) {
|
||||||
|
@ -510,7 +551,8 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||||
p.check(.key_struct)
|
p.check(.key_struct)
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
mut fields := []ast.Field
|
mut ast_fields := []ast.Field
|
||||||
|
mut fields := []types.Field
|
||||||
for p.tok.kind != .rcbr {
|
for p.tok.kind != .rcbr {
|
||||||
if p.tok.kind == .key_pub {
|
if p.tok.kind == .key_pub {
|
||||||
p.check(.key_pub)
|
p.check(.key_pub)
|
||||||
|
@ -518,19 +560,24 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||||
}
|
}
|
||||||
field_name := p.check_name()
|
field_name := p.check_name()
|
||||||
typ := p.parse_type()
|
typ := p.parse_type()
|
||||||
fields << ast.Field{
|
ast_fields << ast.Field{
|
||||||
name: field_name
|
name: field_name
|
||||||
typ: typ
|
typ: typ
|
||||||
}
|
}
|
||||||
|
fields << types.Field{
|
||||||
|
name: field_name
|
||||||
|
type_idx: typ.idx
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.check(.rcbr)
|
p.check(.rcbr)
|
||||||
p.table.register_type(types.Type{
|
p.table.register_type(types.Type{
|
||||||
name: name
|
name: name
|
||||||
|
fields: fields
|
||||||
})
|
})
|
||||||
return ast.StructDecl{
|
return ast.StructDecl{
|
||||||
name: name
|
name: name
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
fields: fields
|
fields: ast_fields
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ x := 10
|
||||||
'
|
'
|
||||||
table := &table.Table{}
|
table := &table.Table{}
|
||||||
prog := parse_file(s, table)
|
prog := parse_file(s, table)
|
||||||
res := gen.cgen([prog])
|
res := gen.cgen([prog], table)
|
||||||
println(res)
|
println(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ fn test_parse_expr() {
|
||||||
program := ast.File{
|
program := ast.File{
|
||||||
stmts: e
|
stmts: e
|
||||||
}
|
}
|
||||||
res := gen.cgen([program])
|
res := gen.cgen([program], table)
|
||||||
println('========')
|
println('========')
|
||||||
println(res)
|
println(res)
|
||||||
println('========')
|
println('========')
|
||||||
|
|
|
@ -6,13 +6,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
|
// struct_fields map[string][]string
|
||||||
pub mut:
|
pub mut:
|
||||||
|
types map[string]types.Type
|
||||||
local_vars []Var
|
local_vars []Var
|
||||||
// fns Hashmap
|
// fns Hashmap
|
||||||
fns map[string]Fn
|
fns map[string]Fn
|
||||||
types map[string]types.Type
|
|
||||||
//
|
//
|
||||||
unknown_calls []ast.CallExpr
|
unknown_calls []ast.CallExpr
|
||||||
|
tmp_cnt int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Var {
|
pub struct Var {
|
||||||
|
@ -26,6 +28,7 @@ pub struct Fn {
|
||||||
pub:
|
pub:
|
||||||
name string
|
name string
|
||||||
args []Var
|
args []Var
|
||||||
|
return_type types.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_table() &Table {
|
pub fn new_table() &Table {
|
||||||
|
@ -109,3 +112,16 @@ pub fn (t mut Table) register_fn(new_fn Fn) {
|
||||||
pub fn (t mut Table) register_type(typ types.Type) {
|
pub fn (t mut Table) register_type(typ types.Type) {
|
||||||
t.types[typ.name] = typ
|
t.types[typ.name] = typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (t &Table) find_type(name string) ?types.Type {
|
||||||
|
typ := t.types[name]
|
||||||
|
if isnil(typ.name.str) || typ.name == '' {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (t mut Table) new_tmp_var() string {
|
||||||
|
t.tmp_cnt++
|
||||||
|
return 'tmp$t.tmp_cnt'
|
||||||
|
}
|
||||||
|
|
|
@ -311,6 +311,9 @@ pub const (
|
||||||
// Precedence returns a tokens precedence if defined, otherwise lowest_prec
|
// Precedence returns a tokens precedence if defined, otherwise lowest_prec
|
||||||
pub fn (tok Token) precedence() int {
|
pub fn (tok Token) precedence() int {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
|
.dot {
|
||||||
|
return 8
|
||||||
|
}
|
||||||
// `++` | `--`
|
// `++` | `--`
|
||||||
.inc, .dec {
|
.inc, .dec {
|
||||||
return 7
|
return 7
|
||||||
|
|
|
@ -3,25 +3,51 @@
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module types
|
module types
|
||||||
|
|
||||||
|
pub enum Kind {
|
||||||
|
struct_
|
||||||
|
builtin
|
||||||
|
enum_
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Type {
|
pub struct Type {
|
||||||
pub:
|
pub:
|
||||||
name string
|
name string
|
||||||
idx int
|
idx int
|
||||||
|
// kind Kind
|
||||||
|
fields []Field
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Field {
|
||||||
|
pub:
|
||||||
|
name string
|
||||||
|
type_idx int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
void_type = Type{
|
void_type = Type{
|
||||||
'void',0}
|
name: 'void'
|
||||||
|
idx: 0
|
||||||
|
}
|
||||||
int_type = Type{
|
int_type = Type{
|
||||||
'int',1}
|
name: 'int'
|
||||||
|
idx: 1
|
||||||
|
}
|
||||||
string_type = Type{
|
string_type = Type{
|
||||||
'string',2}
|
name: 'string'
|
||||||
|
idx: 2
|
||||||
|
}
|
||||||
f64_type = Type{
|
f64_type = Type{
|
||||||
'f64',3}
|
name: 'f64'
|
||||||
|
idx: 3
|
||||||
|
}
|
||||||
bool_type = Type{
|
bool_type = Type{
|
||||||
'bool',4}
|
name: 'bool'
|
||||||
|
idx: 4
|
||||||
|
}
|
||||||
voidptr_type = Type{
|
voidptr_type = Type{
|
||||||
'voidptr',5}
|
name: 'voidptr'
|
||||||
|
idx: 5
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
pub fn check(got, expected &Type) bool {
|
pub fn check(got, expected &Type) bool {
|
||||||
|
|
Loading…
Reference in New Issue