v: initial impl of new type sys w/ pointer & placeholder support (#3323)

pull/3326/head
joe-conigliaro 2020-01-05 03:57:25 +11:00 committed by Alexander Medvednikov
parent 778a1cc34a
commit 2061394ad7
9 changed files with 667 additions and 173 deletions

View File

@ -17,7 +17,7 @@ ForStmt | StructDecl
pub struct ExprStmt {
pub:
expr Expr
typ types.Type
ti types.TypeIdent
}
pub struct IntegerLiteral {
@ -59,7 +59,7 @@ pub:
pub struct Field {
pub:
name string
typ types.Type
ti types.TypeIdent
}
pub struct StructDecl {
@ -71,7 +71,8 @@ pub:
pub struct StructInit {
pub:
typ types.Type
ti types.TypeIdent
// typ types.Type
fields []string
exprs []Expr
}
@ -86,7 +87,8 @@ pub:
pub struct Arg {
pub:
typ types.Type
ti types.TypeIdent
// typ types.Type
name string
}
@ -94,7 +96,8 @@ pub struct FnDecl {
pub:
name string
stmts []Stmt
typ types.Type
ti types.TypeIdent
// typ types.Type
args []Arg
is_pub bool
receiver Field
@ -133,7 +136,8 @@ pub struct VarDecl {
pub:
name string
expr Expr
typ types.Type
ti types.TypeIdent
// typ types.Type
}
pub struct File {
@ -174,7 +178,8 @@ pub:
cond Expr
stmts []Stmt
else_stmts []Stmt
typ types.Type
ti types.TypeIdent
// typ types.Type
left Expr // `a` in `a := if ...`
}
@ -200,7 +205,8 @@ pub:
pub struct ArrayInit {
pub:
exprs []Expr
typ types.Type
ti types.TypeIdent
// typ types.Type
}
// string representaiton of expr

View File

@ -53,12 +53,12 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('int ${it.name}(')
}
else {
g.write('$it.typ.name ${it.name}(')
g.definitions.write('$it.typ.name ${it.name}(')
g.write('$it.ti.type_name ${it.name}(')
g.definitions.write('$it.ti.type_name ${it.name}(')
}
for arg in it.args {
g.write(arg.typ.name + ' ' + arg.name)
g.definitions.write(arg.typ.name + ' ' + arg.name)
g.write(arg.ti.type_name + ' ' + arg.name)
g.definitions.write(arg.ti.type_name + ' ' + arg.name)
}
g.writeln(') { ')
if !is_main {
@ -78,7 +78,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.VarDecl {
g.write('$it.typ.name $it.name = ')
g.write('$it.ti.type_name $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
@ -98,7 +98,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.StructDecl {
g.writeln('typedef struct {')
for field in it.fields {
g.writeln('\t$field.typ.name $field.name;')
g.writeln('\t$field.ti.type_name $field.name;')
}
g.writeln('} $it.name;')
}
@ -154,7 +154,7 @@ fn (g mut Gen) expr(node ast.Expr) {
}
// `user := User{name: 'Bob'}`
ast.StructInit {
g.writeln('($it.typ.name){')
g.writeln('($it.ti.type_name){')
for i, field in it.fields {
g.write('\t.$field = ')
g.expr(it.exprs[i])
@ -173,7 +173,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(')')
}
ast.ArrayInit {
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t')
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t')
for expr in it.exprs {
g.expr(expr)
g.write(', ')
@ -200,7 +200,7 @@ fn (g mut Gen) expr(node ast.Expr) {
// 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 {
if it.ti.type_kind != ._void {
tmp = g.table.new_tmp_var()
// g.writeln('$it.typ.name $tmp;')
}
@ -209,7 +209,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.writeln(') {')
for i, stmt in it.stmts {
// Assign ret value
if i == it.stmts.len - 1 && it.typ.idx != types.void_type.idx {
if i == it.stmts.len - 1 && it.ti.type_kind != ._void {
// g.writeln('$tmp =')
println(1)
}

View File

@ -40,9 +40,9 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.FnDecl {
g.write('/** @return { $it.typ.name } **/\nfunction ${it.name}(')
g.write('/** @return { $it.ti.type_name } **/\nfunction ${it.name}(')
for arg in it.args {
g.write(' /** @type { arg.typ.name } **/ $arg.name')
g.write(' /** @type { arg.ti.type_name } **/ $arg.name')
}
g.writeln(') { ')
for stmt in it.stmts {
@ -56,7 +56,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.VarDecl {
g.write('var /* $it.typ.name */ $it.name = ')
g.write('var /* $it.ti.type_name */ $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
@ -72,7 +72,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
ast.StructDecl {
// g.writeln('typedef struct {')
// for field in it.fields {
// g.writeln('\t$field.typ.name $field.name;')
// g.writeln('\t$field.ti.type_name $field.name;')
// }
g.writeln('var $it.name = function() {};')
}
@ -115,7 +115,7 @@ fn (g mut JsGen) expr(node ast.Expr) {
}
// `user := User{name: 'Bob'}`
ast.StructInit {
g.writeln('/*$it.typ.name*/{')
g.writeln('/*$it.ti.type_name*/{')
for i, field in it.fields {
g.write('\t$field : ')
g.expr(it.exprs[i])

View File

@ -337,7 +337,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.VarDecl {
g.write('$it.typ.name $it.name = ')
g.write('$it.ti.type_name $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
@ -354,7 +354,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.StructDecl {
g.writeln('typedef struct {')
for field in it.fields {
g.writeln('\t$field.typ.name $field.name;')
g.writeln('\t$field.ti.type_name $field.name;')
}
g.writeln('} $it.name;')
}
@ -394,13 +394,13 @@ fn (g mut Gen) expr(node ast.Expr) {
g.expr(it.left)
g.write(' $it.op.str() ')
g.expr(it.right)
// if typ.name != typ2.name {
// verror('bad types $typ.name $typ2.name')
// if ti.type_name != typ2.name {
// verror('bad types $ti.type_name $typ2.name')
// }
}
// `user := User{name: 'Bob'}`
ast.StructInit {
g.writeln('($it.typ.name){')
g.writeln('($it.ti.type_name){')
for i, field in it.fields {
g.write('\t.$field = ')
g.expr(it.exprs[i])
@ -426,7 +426,7 @@ fn (g mut Gen) expr(node ast.Expr) {
}
ast.ArrayInit {
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t')
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t')
for expr in it.exprs {
g.expr(expr)
g.write(', ')

View File

@ -13,20 +13,20 @@ import (
os
)
pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) {
// println('got fn call')
tok := p.tok
fn_name := p.check_name()
p.check(.lpar)
mut is_unknown := false
mut args := []ast.Expr
mut return_type := types.void_type
mut return_ti := types.new_base_ti(._void, 0)
if f := p.table.find_fn(fn_name) {
return_type = f.return_type
return_ti = f.return_ti
for i, arg in f.args {
e,typ := p.expr(0)
if !types.check(arg.typ, typ) {
p.error('cannot use type `$typ.name` as type `$arg.typ.name` in argument to `$fn_name`')
e,ti := p.expr(0)
if !types.check(arg.ti, ti) {
p.error('cannot use type `$ti.type_name` as type `$arg.ti.type_name` in argument to `$fn_name`')
}
args << e
if i < f.args.len - 1 {
@ -59,7 +59,7 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
if is_unknown {
p.table.unknown_calls << node
}
return node,return_type
return node,return_ti
}
fn (p mut Parser) fn_decl() ast.FnDecl {
@ -71,17 +71,17 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.check(.key_fn)
// Receiver?
mut rec_name := ''
mut rec_type := types.void_type
mut rec_ti := types.new_base_ti(._void, 0)
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()
rec_ti = p.parse_ti()
p.table.register_var(table.Var{
name: rec_name
typ: rec_type
ti: rec_ti
})
p.check(.rpar)
}
@ -98,16 +98,16 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.check(.comma)
arg_names << p.check_name()
}
typ := p.parse_type()
ti := p.parse_ti()
for arg_name in arg_names {
arg := table.Var{
name: arg_name
typ: typ
ti: ti
}
args << arg
p.table.register_var(arg)
ast_args << ast.Arg{
typ: typ
ti: ti
name: arg_name
}
}
@ -117,26 +117,26 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
}
p.check(.rpar)
// Return type
mut typ := types.void_type
if p.tok.kind == .name {
typ = p.parse_type()
p.return_type = typ
mut ti := types.new_base_ti(._void, 0)
if p.tok.kind in [.amp, .name] {
ti = p.parse_ti()
p.return_ti = ti
}
p.table.register_fn(table.Fn{
name: name
args: args
return_type: typ
return_ti: ti
})
stmts := p.parse_block()
return ast.FnDecl{
name: name
stmts: stmts
typ: typ
ti: ti
args: ast_args
is_pub: is_pub
receiver: ast.Field{
name: rec_name
typ: rec_type
ti: rec_ti
}
}
}

View File

@ -21,7 +21,7 @@ mut:
peek_tok token.Token
// vars []string
table &table.Table
return_type types.Type
return_ti types.TypeIdent
is_c bool
}
@ -35,6 +35,126 @@ pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
return p.stmt()
}
pub fn (p mut Parser) parse_ti() types.TypeIdent {
defer {
p.next()
}
mut nr_muls := 0
if p.tok.kind == .amp {
p.check(.amp)
nr_muls = 1
}
name := p.tok.lit
if nr_muls > 0 {
println('## POINTER: $name')
}
match name {
'voidptr' {
return types.new_base_ti(._voidptr, nr_muls)
}
'byteptr' {
return types.new_base_ti(._byteptr, nr_muls)
}
'charptr' {
return types.new_base_ti(._charptr, nr_muls)
}
'164' {
return types.new_base_ti(._i16, nr_muls)
}
'int' {
return types.new_base_ti(._int, nr_muls)
}
'i64' {
return types.new_base_ti(._i64, nr_muls)
}
'byte' {
return types.new_base_ti(._byte, nr_muls)
}
'u16' {
return types.new_base_ti(._u16, nr_muls)
}
'u32' {
return types.new_base_ti(._u32, nr_muls)
}
'u64' {
return types.new_base_ti(._u64, nr_muls)
}
'f32' {
return types.new_base_ti(._f32, nr_muls)
}
'f64' {
return types.new_base_ti(._f64, nr_muls)
}
'string' {
return types.new_base_ti(._string, nr_muls)
}
'char' {
return types.new_base_ti(._char, nr_muls)
}
'bool' {
return types.new_base_ti(._bool, nr_muls)
}
else {
// array
if p.tok.kind == .lsbr {
p.check(.lsbr)
// fixed array
if p.tok.kind == .number {
fixed_size := p.tok.lit.int()
p.check(.rsbr)
elem_ti := p.parse_ti()
array_fixed_type := types.ArrayFixed{
name: 'array_fixed_$elem_ti.type_name'
size: fixed_size
elem_type_idx: elem_ti.type_idx
}
idx := p.table.find_or_register_array_fixed(array_fixed_type)
return types.new_ti(._array_fixed, array_fixed_type.name, idx, nr_muls)
}
p.check(.rsbr)
// array
elem_ti := p.parse_ti()
array_type := types.Array{
name: 'array_$elem_ti.type_name'
elem_type_idx: elem_ti.type_idx
}
idx := p.table.find_or_register_array(array_type)
return types.new_ti(._array, array_type.name, idx, nr_muls)
}
// map
else if name == 'map' {
p.next()
p.check(.lsbr)
key_ti := p.parse_ti()
p.check(.rsbr)
value_ti := p.parse_ti()
map_type := types.Map{
name: 'map_${key_ti.type_name}_${value_ti.type_name}'
key_type_idx: key_ti.type_idx,
value_type_idx: value_ti.type_idx
}
idx := p.table.find_or_register_map(map_type)
return types.new_ti(._map, map_type.name, idx, nr_muls)
} else {
// struct / enum
mut idx := p.table.find_type_idx(name)
// add placeholder
if idx == 0 {
idx = p.table.add_placeholder_type(name)
}
return types.new_ti(._placeholder, name, idx, nr_muls)
}
// typ := p.table.types[p.tok.lit]
// if isnil(typ.name.str) || typ.name == '' {
// p.error('undefined type `$p.tok.lit`')
// }
// println('RET Typ $typ.name')
// typ
}
}
}
pub fn parse_file(path string, table &table.Table) ast.File {
println('parse file "$path"')
text := os.read_file(path) or {
@ -74,16 +194,16 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
}
// former get_type()
pub fn (p mut Parser) parse_type() types.Type {
typ := p.table.find_type(p.tok.lit) or {
// typ := p.table.types[p.tok.lit]
// if isnil(typ.name.str) || typ.name == '' {
p.error('undefined type `$p.tok.lit`')
exit(0)
}
p.next()
return typ
}
// pub fn (p mut Parser) parse_ti() types.Type {
// typ := p.table.find_type(p.tok.lit) or {
// // typ := p.table.types[p.tok.lit]
// // if isnil(typ.name.str) || typ.name == '' {
// p.error('undefined type `$p.tok.lit`')
// exit(0)
// }
// p.next()
// return typ
// }
pub fn (p mut Parser) read_first_token() {
// need to call next() twice to get peek token and current token
@ -157,7 +277,7 @@ pub fn (p mut Parser) stmt() ast.Stmt {
p.error('wrong pub keyword usage')
return ast.Stmt{}
}
}
}
// .key_const {
// return p.const_decl()
// }
@ -184,10 +304,10 @@ pub fn (p mut Parser) stmt() ast.Stmt {
return p.for_statement()
}
else {
expr,typ := p.expr(0)
expr,ti := p.expr(0)
return ast.ExprStmt{
expr: expr
typ: typ
ti: ti
}
}
}
@ -233,11 +353,12 @@ pub fn (p &Parser) warn(s string) {
}
// Implementation of Pratt Precedence
pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.TypeIdent) {
// println('expr at ' + p.tok.str())
// null denotation (prefix)
mut node := ast.Expr{}
mut typ := types.void_type
// mut typ := types.void_type
mut ti := types.new_base_ti(._void, 0)
match p.tok.kind {
.name {
/*
@ -254,13 +375,13 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
}
// fn call
if p.peek_tok.kind == .lpar {
x,typ2 := p.call_expr() // TODO `node,typ :=` should work
x,ti2 := p.call_expr() // TODO `node,typ :=` should work
node = x
typ = typ2
ti = ti2
}
// struct init
else if p.peek_tok.kind == .lcbr {
typ = p.parse_type()
ti = p.parse_ti()
// println('sturct init typ=$typ.name')
p.check(.lcbr)
mut field_names := []string
@ -275,7 +396,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
exprs << expr
}
node = ast.StructInit{
typ: typ
ti: ti
exprs: exprs
fields: field_names
}
@ -290,46 +411,46 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
p.error('unknown variable `$p.tok.lit`')
exit(0)
}
typ = var.typ
ti = var.ti
// ///typ = types.int_type
p.next()
}
}
.lsbr {
node,typ = p.array_init()
node,ti = p.array_init()
}
.key_true, .key_false {
node = ast.BoolLiteral{
val: p.tok.kind == .key_true
}
typ = types.bool_type
ti = types.new_base_ti(._bool, 0)
p.next()
}
.str {
node,typ = p.parse_string_literal()
node,ti = p.parse_string_literal()
}
.number {
node,typ = p.parse_number_literal()
node,ti = p.parse_number_literal()
}
.key_if {
node,typ = p.if_expr()
node,ti = p.if_expr()
}
.lpar {
p.check(.lpar)
p.next()
node,typ = p.expr(token.lowest_prec)
node,ti = p.expr(token.lowest_prec)
p.check(.rpar)
}
else {
if p.tok.is_unary() {
pt := p.tok
p.next()
expr,t2 := p.expr(token.lowest_prec)
expr,ti2 := p.expr(token.lowest_prec)
node = ast.UnaryExpr{
left: expr
op: pt.kind
}
typ = t2
ti = ti2
}
else {
p.error('expr(): unknown token ' + p.tok.str() + ' kind=$p.tok.kind')
@ -340,30 +461,36 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
for rbp < p.tok.precedence() {
prev_tok := p.tok
p.next()
mut t2 := types.Type{}
// mut t2 := types.Type{}
mut ti2 := types.new_base_ti(._void, 0)
// left denotation (infix / postfix)
if prev_tok.is_right_assoc() && !p.tok.kind in [.plus, .minus] && // think of better way to handle this
!p.peek_tok.kind in [.number, .name] {
// supposed to be only unary, additive handled in left asssoc
mut expr := ast.Expr{}
expr,t2 = p.expr(prev_tok.precedence() - 1)
expr,ti2 = p.expr(prev_tok.precedence() - 1)
node = ast.BinaryExpr{
left: node
op: prev_tok.kind
right: expr
}
// println(t2.name + 'OOO')
if !types.check(&typ, &t2) {
if !types.check(&ti, &ti2) {
println('tok: $prev_tok.str()')
p.error('cannot convert `$t2.name` to `$typ.name`')
p.error('cannot convert `$ti2.type_name` to `$ti.type_name`')
}
}
else if prev_tok.is_left_assoc() {
// postfix `.`
if prev_tok.kind == .dot {
p.warn('dot prev_tok = $prev_tok.str() typ=$typ.name')
p.warn('dot prev_tok = $prev_tok.str() typ=$ti.type_name')
// p.next()
field := p.check_name()
if !ti.type_kind in [._placeholder, ._struct] {
println('kind: $ti.str()')
p.error('cannot access field, `$ti.type_name` is not a struct')
}
typ := p.table.types[ti.type_idx] as types.Struct
mut ok := false
for f in typ.fields {
if f.name == field {
@ -388,14 +515,15 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
}
else {
mut expr := ast.Expr{}
expr,t2 = p.expr(prev_tok.precedence() - 1)
expr,ti2 = p.expr(prev_tok.precedence() - 1)
if prev_tok.is_relational() {
typ = types.bool_type
// typ = types.bool_type
ti = types.new_base_ti(._bool, 0)
}
else {
typ = t2
ti = ti2
}
// println(t2.name + '222')
// println(ti2.type_name + '222')
node = ast.BinaryExpr{
left: node
op: prev_tok.kind
@ -404,7 +532,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
}
}
}
return node,typ
return node,ti
}
[inline]
@ -432,8 +560,9 @@ fn (p mut Parser) for_statement() ast.ForStmt {
}
}
// `for cond {`
cond,typ := p.expr(0)
if !types.check(types.bool_type, typ) {
cond,ti := p.expr(0)
// if !types.check(types.bool_type, ti) {
if ti.type_kind != ._bool {
p.error('non-bool used as for condition')
}
stmts := p.parse_block()
@ -443,11 +572,12 @@ 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.TypeIdent) {
mut node := ast.Expr{}
p.check(.key_if)
cond,cond_type := p.expr(0)
if !types.check(types.bool_type, cond_type) {
// if !types.check(types.bool_type, cond_type) {
if cond_type.type_kind != ._bool {
p.error('non-bool used as if condition')
}
stmts := p.parse_block()
@ -457,13 +587,14 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
p.check(.key_else)
else_stmts = p.parse_block()
}
mut typ := types.void_type
// mut typ := types.void_type
mut ti := types.new_base_ti(._void, 0)
// mut left := ast.Expr{}
// If the last statement is an expression, return its type
match stmts[stmts.len - 1] {
ast.ExprStmt {
p.warn('if expr ret $it.typ.name')
typ = it.typ
p.warn('if expr ret $it.ti.type_name')
ti = it.ti
// return node,it.typ
// left =
}
@ -473,35 +604,37 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
cond: cond
stmts: stmts
else_stmts: else_stmts
typ: typ
ti: ti
// left: left
}
return node,typ
return node,ti
}
fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) {
fn (p mut Parser) parse_string_literal() (ast.Expr,types.TypeIdent) {
mut node := ast.Expr{}
node = ast.StringLiteral{
val: p.tok.lit
}
p.next()
return node,types.string_type
// return node,types.string_type
return node, types.new_base_ti(._string, 0)
}
fn (p mut Parser) array_init() (ast.Expr,types.Type) {
fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) {
p.check(.lsbr)
mut val_type := types.void_type
// mut val_type := types.void_type
mut val_ti := types.new_base_ti(._void, 0)
mut exprs := []ast.Expr
mut i := 0
for p.tok.kind != .rsbr {
expr,typ := p.expr(0)
expr,ti := p.expr(0)
// The first element's type
if i == 0 {
val_type = typ
val_ti = ti
}
else if !types.check(val_type, typ) {
p.error('expected array element with type `$val_type.name`')
else if !types.check(val_ti, ti) {
p.error('expected array element with type `$val_ti.type_name`')
}
exprs << expr
i++
@ -511,32 +644,32 @@ fn (p mut Parser) array_init() (ast.Expr,types.Type) {
}
mut node := ast.Expr{}
node = ast.ArrayInit{
typ: val_type
ti: val_ti
exprs: exprs
}
p.check(.rsbr)
return node,val_type
return node,val_ti
}
fn (p mut Parser) parse_number_literal() (ast.Expr,types.Type) {
fn (p mut Parser) parse_number_literal() (ast.Expr,types.TypeIdent) {
lit := p.tok.lit
mut node := ast.Expr{}
mut typ := types.int_type
mut ti := types.new_base_ti(._int, 0)
if lit.contains('.') {
node = ast.FloatLiteral{
// val: lit.f64()
val: lit
}
typ = types.f64_type
ti = types.new_base_ti(._f64, 0)
}
else {
node = ast.IntegerLiteral{
val: lit.int()
}
typ = types.int_type
// ti = types.new_base_ti(._int, 0)
}
p.next()
return node,typ
return node,ti
}
fn (p mut Parser) module_decl() ast.Module {
@ -569,18 +702,22 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
p.check(.colon)
}
field_name := p.check_name()
typ := p.parse_type()
ti := p.parse_ti()
ast_fields << ast.Field{
name: field_name
typ: typ
ti: ti
}
fields << types.Field{
name: field_name
type_idx: typ.idx
type_idx: ti.type_idx
}
}
p.check(.rcbr)
p.table.register_type(types.Type{
if name in p.table.type_idxs {
println('placeholder exists: $name')
}
println('about to register: $name')
p.table.register_struct(types.Struct{
name: name
fields: fields
})
@ -594,8 +731,8 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
fn (p mut Parser) return_stmt() ast.Return {
p.next()
expr,t := p.expr(0)
if !types.check(p.return_type, t) {
p.error('cannot use `$t.name` as type `$p.return_type.name` in return argument')
if !types.check(p.return_ti, t) {
p.error('cannot use `$t.type_name` as type `$p.return_ti.type_name` in return argument')
}
return ast.Return{
expr: expr
@ -621,7 +758,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
}
p.table.register_var(table.Var{
name: name
typ: t
ti: t
is_mut: is_mut
})
// println(p.table.names)
@ -630,7 +767,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
name: name
expr: expr // p.expr(token.lowest_prec)
typ: t
ti: t
}
}

View File

@ -8,7 +8,9 @@ import (
pub struct Table {
// struct_fields map[string][]string
pub mut:
types map[string]types.Type
// types map[string]types.Type
types []types.Type
type_idxs map[string]int
local_vars []Var
// fns Hashmap
fns map[string]Fn
@ -20,7 +22,7 @@ pub mut:
pub struct Var {
pub:
name string
typ types.Type
ti types.TypeIdent
is_mut bool
}
@ -28,17 +30,23 @@ pub struct Fn {
pub:
name string
args []Var
return_type types.Type
return_ti types.TypeIdent
}
pub fn new_table() &Table {
// mut t := &Table{}
// t.register_type(types.void_type)
// t.register_type(types.int_type)
// t.register_type(types.string_type)
// t.register_type(types.f64_type)
// t.register_type(types.bool_type)
// t.register_type(types.voidptr_type)
mut t := &Table{}
t.register_type(types.void_type)
t.register_type(types.int_type)
t.register_type(types.string_type)
t.register_type(types.f64_type)
t.register_type(types.bool_type)
t.register_type(types.voidptr_type)
// add dummy type at 0 so nothing can go there
// save index check, 0 will mean not found
t.types << types.Type{}
t.type_idxs['dymmy_type_at_idx_0'] = 0
return t
}
@ -109,19 +117,106 @@ pub fn (t mut Table) register_fn(new_fn Fn) {
t.fns[new_fn.name] = new_fn
}
pub fn (t mut Table) register_type(typ types.Type) {
t.types[typ.name] = typ
pub fn (t mut Table) register_struct(typ types.Struct) int {
mut t2 := types.Type{}
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
ex_type := t.types[existing_idx]
match ex_type {
types.Placeholder {
// override placeholder
println('placeholder exists: $it.name overidding')
t2 = {typ| idx: existing_idx}
t.types[existing_idx] = t2
return existing_idx
}
else {}
}
}
// register
println('registering: $typ.name')
idx := t.types.len
t.type_idxs[typ.name] = idx
t2 = {typ| idx: idx}
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_map(typ types.Map) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_array(typ types.Array) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_array_fixed(typ types.ArrayFixed) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
[inline]
pub fn (t &Table) find_type_idx(name string) int {
return t.type_idxs[name]
}
pub fn (t mut Table) add_placeholder_type(name string) int {
idx := t.types.len
t.type_idxs[name] = t.types.len
mut pt := types.Type{}
pt = types.Placeholder{
idx: idx
name: name
}
println('added placeholder: $name - $idx ')
t.types << pt
return idx
}
pub fn (t &Table) find_type(name string) ?types.Type {
typ := t.types[name]
if isnil(typ.name.str) || typ.name == '' {
return none
idx := t.type_idxs[name]
if idx > 0 {
return t.types[idx]
}
return typ
return none
}
pub fn (t mut Table) new_tmp_var() string {
t.tmp_cnt++
return 'tmp$t.tmp_cnt'
}

View File

@ -4,16 +4,208 @@
module types
pub enum Kind {
struct_
builtin
enum_
_placeholder,
_void,
_voidptr,
_charptr,
_byteptr,
_const,
_enum,
_struct,
_int,
_i8,
_i16,
_i64,
_byte,
_u16,
_u32,
_u64,
_f32,
_f64,
_string,
_char,
_bool,
_array,
_array_fixed,
_map,
_multi_return,
_variadic
}
pub struct Type {
pub struct TypeIdent {
pub:
type_idx int
type_kind Kind
type_name string
nr_muls int
}
[inline]
pub fn new_ti(type_kind Kind, type_name string, type_idx int, nr_muls int) TypeIdent {
return TypeIdent{
type_idx: type_idx
type_kind: type_kind
type_name: type_name
nr_muls: nr_muls
}
}
[inline]
pub fn new_base_ti(type_kind Kind, nr_muls int) TypeIdent {
return TypeIdent{
type_kind: type_kind
type_name: type_kind.str()
nr_muls: nr_muls
}
}
[inline]
pub fn (ti &TypeIdent) is_ptr() bool {
return ti.nr_muls > 0
}
[inline]
pub fn (ti &TypeIdent) is_int() bool {
return ti.type_kind in [._i8, ._i16, ._int, ._i64, ._byte, ._u16, ._u32, ._u64]
}
[inline]
pub fn (ti &TypeIdent) is_float() bool {
return ti.type_kind in [._f32, ._f64]
}
[inline]
pub fn (ti &TypeIdent) is_number() bool {
return ti.is_int() || ti.is_float()
}
pub fn (ti &TypeIdent) str() string {
return '$ti.type_kind.str() $ti.type_idx: $ti.type_name ($ti.nr_muls)'
}
pub fn check(got, expected &TypeIdent) bool {
if got.type_idx != expected.type_idx {
return false
}
return true
}
pub fn (t Kind) str() string {
t_str := match t {
._placeholder {
'placeholder'
}
._void {
'void'
}
._voidptr {
'voidptr'
}
._charptr {
'charptr'
}
._byteptr {
'byteptr'
}
._const {
'const'
}
._enum {
'enum'
}
._struct {
'struct'
}
._int {
'int'
}
._i8 {
'i8'
}
._i16 {
'i16'
}
._i64 {
'i64'
}
._byte {
'byte'
}
._u16 {
'u18'
}
._f32 {
'f32'
}
._f64 {
'f64'
}
._string {
'string'
}
._char {
'char'
}
._bool {
'bool'
}
._array {
'array'
}
._array_fixed {
'array_fixed'
}
._map {
'map'
}
._multi_return {
'multi_return'
}
._variadic {
'variadic'
}
else {
'unknown'
}
}
return t_str
}
pub type Type = Placeholder | Void | Voidptr | Charptr | Byteptr | Const | Enum | Struct |
Int | Float | String | Char | Byte | Bool | Array | ArrayFixed | Map | MultiReturn | Variadic
pub struct Placeholder {
pub:
idx int
name string
kind Kind
}
pub struct Void {}
pub struct Voidptr {}
pub struct Charptr {}
pub struct Byteptr {}
pub struct Const {
pub:
idx int
name string
}
pub struct Enum {
pub:
idx int
name string
}
pub struct Struct {
pub:
name string
idx int
// kind Kind
name string
fields []Field
}
@ -23,36 +215,95 @@ pub:
type_idx int
}
pub const (
void_type = Type{
name: 'void'
idx: 0
}
int_type = Type{
name: 'int'
idx: 1
}
string_type = Type{
name: 'string'
idx: 2
}
f64_type = Type{
name: 'f64'
idx: 3
}
bool_type = Type{
name: 'bool'
idx: 4
}
voidptr_type = Type{
name: 'voidptr'
idx: 5
}
)
pub fn check(got, expected &Type) bool {
if got.idx != expected.idx {
return false
}
return true
pub struct Int {
pub:
bit_size u32
is_unsigned bool
}
pub struct Float {
bit_size u32
}
pub struct String {}
pub struct Char {}
pub struct Byte {}
pub struct Bool {}
pub struct Array {
pub:
idx int
name string
elem_type_kind Kind
elem_type_idx int
nr_dims int
}
pub struct ArrayFixed {
pub:
idx int
name string
elem_type_kind Kind
elem_type_idx int
size int
}
pub struct Map {
pub:
idx int
name string
key_type_kind Kind
key_type_idx int
value_type_kind Kind
value_type_idx int
}
pub struct MultiReturn {
pub:
elem_type_kinds []Kind
elem_type_idxs []int
}
pub struct Variadic {
pub:
elem_type_kind Kind
elem_type_idx int
}
pub fn (t Void) str() string { return 'void' }
pub fn (t Voidptr) str() string { return 'voidptr' }
pub fn (t Charptr) str() string { return 'charptr' }
pub fn (t Byteptr) str() string { return 'Byteptr' }
pub fn (t Const) str() string { return t.name }
pub fn (t Enum) str() string { return t.name }
pub fn (t Struct) str() string { return t.name }
pub fn (t Int) str() string { return if t.is_unsigned {'u$t.bit_size' } else { 'i$t.bit_size' } }
pub fn (t Float) str() string { return 'f$t.bit_size' }
pub fn (t String) str() string { return 'string' }
pub fn (t Char) str() string { return 'char' }
pub fn (t Byte) str() string { return 'byte' }
pub fn (t Array) str() string { return t.name }
pub fn (t ArrayFixed) str() string { return t.name }
pub fn (t Map) str() string { return t.name }
pub fn (t MultiReturn) str() string { return 'multi_return_$t.elem_type_kinds.str()' }
pub fn (t Variadic) str() string { return 'variadic_$t.elem_type_kind.str()' }
pub const (
void_type = Void{}
voidptr_type = Voidptr{}
charptr_type = Charptr{}
byteptr_type = Byteptr{}
int_type = Int{32, false}
i64_type = Int{64, false}
byte_type = Int{8, true}
u32_type = Int{32, true}
u64_type = Int{64, true}
f32_type = Float{32}
f64_type = Float{64}
string_type = String{}
char_type = Char{}
bool_type = Bool{}
)

View File

@ -0,0 +1,5 @@
module types
fn test_types() {
}