1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

new AST built with sum types

This commit is contained in:
Alexander Medvednikov
2019-12-22 04:34:37 +03:00
parent 803ded3dec
commit ca284482cb
15 changed files with 1521 additions and 38 deletions

View File

@ -47,8 +47,12 @@ fn (p mut Parser) bool_expression() string {
p.error('expr() returns empty type')
}
if expected != typ && expected in p.table.sum_types { // TODO perf
p.cgen.set_placeholder(start_ph, '/*KUK*/($expected) { .obj = ($typ[]) { ')
p.gen('}, .typ = 1}')//${val}_type }')
p.cgen.set_placeholder(start_ph,
//'/*SUM TYPE CAST*/($expected) { .obj = &($typ[]) { ')
'/*SUM TYPE CAST*/($expected) { .obj = memdup(& ')
tt := typ.all_after('_') // TODO
//p.gen('}, .typ = SumType_${tt} }')//${val}_type }')
p.gen(', sizeof($typ) ), .typ = SumType_${tt} }')//${val}_type }')
}
return typ
@ -369,7 +373,7 @@ fn (p mut Parser) name_expr() string {
//println(q)
//println(q[idx])
arg_type := q[idx]
p.gen('($enum_type.name) { .obj = ($arg_type[]) { ')
p.gen('($enum_type.name) { .obj = ($arg_type[]) { ')
p.bool_expression()
p.check(.rpar)
p.gen('}, .typ = ${val}_type }')

View File

@ -220,7 +220,7 @@ fn (p mut Parser) fn_decl() {
mut f := Fn{
mod: p.mod
is_public: is_pub || p.is_vh // functions defined in .vh are always public
is_unsafe: p.attr == 'unsafe_fn'
is_deprecated: p.attr == 'deprecated'
comptime_define: if p.attr.starts_with('if ') { p.attr[3..] } else { '' }
@ -799,7 +799,7 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
if f.is_method {
receiver := f.args.first()
mut receiver_is_interface := false
if receiver.typ.ends_with('er') {
if receiver.typ.ends_with('er') || receiver.typ[0] == `I` {
// I absolutely love this syntax
// `s.speak()` =>
// `((void (*)())(Speaker_name_table[s._interface_idx][1]))(s._object);
@ -893,7 +893,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
typ: typ
is_arg: true
// is_mut: is_mut
line_nr: p.scanner.line_nr
token_idx: p.cur_tok_index()
}
@ -1083,7 +1083,7 @@ fn (p mut Parser) fn_call_args(f mut Fn, generic_param_types []string) {
// fn run(r Animal) { ... }
// `run(dog)` adds `Dog` to the `Animal` interface.
// This is needed to generate an interface table.
if arg.typ.ends_with('er') {
if arg.typ.ends_with('er') || arg.typ[0] == `I` {
t := p.table.find_type(arg.typ)
if t.cat == .interface_ {
// perform((Speaker) { ._object = &dog,

View File

@ -16,6 +16,9 @@ fn (p mut Parser) match_statement(is_expr bool) string {
if typ.starts_with('array_') {
p.error('arrays cannot be compared')
}
is_sum_type := typ in p.table.sum_types
mut sum_child_type := ''
// is it safe to use p.cgen.insert_before ???
tmp_var := p.get_tmp()
p.cgen.insert_before('$typ $tmp_var = $expr;')
@ -111,6 +114,7 @@ fn (p mut Parser) match_statement(is_expr bool) string {
}
ph := p.cgen.add_placeholder()
// Multiple checks separated by comma
p.open_scope()
mut got_comma := false
for {
if got_comma {
@ -121,11 +125,26 @@ fn (p mut Parser) match_statement(is_expr bool) string {
got_string = true
p.gen('string_eq($tmp_var, ')
}
else if is_sum_type {
p.gen('${tmp_var}.typ == ')
}
else {
p.gen('$tmp_var == ')
}
p.expected_type = typ
p.check_types(p.bool_expression(), typ)
// `match node { ast.BoolExpr { it := node as BoolExpr ... } }`
if is_sum_type {
sum_child_type = p.get_type2().name
tt := sum_child_type.all_after('_')
p.gen('SumType_$tt')
//println('got child $sum_child_type')
p.register_var(Var{
name: 'it'
typ: sum_child_type
})
} else {
p.check_types(p.bool_expression(), typ)
}
p.expected_type = ''
if got_string {
p.gen(')')
@ -169,12 +188,16 @@ fn (p mut Parser) match_statement(is_expr bool) string {
p.fspace()
p.check(.lcbr)
p.genln('{ ')
if is_sum_type {
p.genln(' $sum_child_type it = *($sum_child_type*)$tmp_var .obj ;')
}
p.statements()
all_cases_return = all_cases_return && p.returns
// p.gen(')')
}
i++
p.fgen_nl()
p.close_scope()
}
p.error('match must be exhaustive')
// p.returns = false // only get here when no default, so return is not guaranteed
@ -229,12 +252,12 @@ fn (p mut Parser) if_statement(is_expr bool, elif_depth int) string {
name: var_name
typ: typ
is_mut: false // TODO
is_used: true // TODO
// is_alloc: p.is_alloc || typ.starts_with('array_')
// line_nr: p.tokens[ var_token_idx ].line_nr
// token_idx: var_token_idx
})
p.statements()
p.close_scope()

View File

@ -787,7 +787,7 @@ fn (p mut Parser) type_decl() {
}
p.check(.key_type)
p.fspace()
name := p.check_name()
mut name := p.check_name()
p.fspace()
// V used to have 'type Foo struct', many Go users might use this syntax
if p.tok == .key_struct {
@ -801,6 +801,9 @@ fn (p mut Parser) type_decl() {
// Sum type
is_sum := p.tok == .pipe
if is_sum {
if !p.builtin_mod && p.mod != 'main' {
name = p.prepend_mod(name)
}
// Register the first child (name we already parsed)
/*
p.table.register_type(Type{
@ -811,26 +814,21 @@ fn (p mut Parser) type_decl() {
})
*/
// Register the rest of them
mut idx := 0
for p.tok == .pipe {
idx++
p.next()
child := p.check_name()
child_type_name := p.check_name()
if p.pass == .main {
// Update the type's parent
println('child=$child parent=$name')
mut t := p.table.find_type(child)
//println('child=$child_type_name parent=$name')
mut t := p.find_type(child_type_name)
if t.name == '' {
p.error('unknown type `$child`')
p.error('qunknown type `$child_type_name`')
}
t.parent = name
p.table.rewrite_type(t)
/*
p.table.register_type(Type{
parent: name
name: child
mod: p.mod
is_public: is_pub
})
*/
p.cgen.consts << '#define SumType_$child_type_name $idx // DEF2'
}
}
if p.pass == .decl {
@ -838,7 +836,7 @@ fn (p mut Parser) type_decl() {
println(p.table.sum_types)
}
// Register the actual sum type
println('reging sum $name')
//println('registering sum $name')
p.table.register_type(Type{
name: name
mod: p.mod

View File

@ -15,7 +15,7 @@ const (
error_context_after = 2 // ^^^ same, but after
)
struct Scanner {
pub struct Scanner {
mut:
file_path string
text string

View File

@ -38,7 +38,7 @@ fn (p mut Parser) struct_decl(generic_param_types []string) {
if !p.builtin_mod && !name[0].is_capital() {
p.error('mod=$p.mod struct names must be capitalized: use `struct ${name.capitalize()}`')
}
if is_interface && !name.ends_with('er') {
if is_interface && !name.ends_with('er') && name[0] != `I` {
p.error('interface names temporarily have to end with `er` (e.g. `Speaker`, `Reader`)')
}
mut generic_types := map[string]string

View File

@ -594,9 +594,9 @@ fn (t &Table) find_type(name_ string) Type {
}
fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
if p.fileis('type_test') {
println('got=$got_ exp=$expected_')
}
//if p.fileis('type_test') {
//println('got=$got_ exp=$expected_')
//}
mut got := got_
mut expected := expected_
// p.log('check types got="$got" exp="$expected" ')
@ -724,18 +724,17 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
got = got.replace('*', '').replace('ptr', '')
if got != expected {
// Interface check
if expected.ends_with('er') {
if expected.ends_with('er') || expected[0] == `I` {
if p.satisfies_interface(expected, got, throw) {
return true
}
}
// Sum type
println(expected)
if expected in p.table.sum_types {
println('checking sum')
//println('checking sum')
child := p.table.find_type(got)
if child.parent == expected {
println('yep $expected')
//println('yep $expected')
return true
}
}

View File

@ -20,9 +20,7 @@ fn test_person_str() {
struct Foo {}
struct WTF {
wtf int
}
type Expr = Foo | BoolExpr | BinExpr | UnaryExpr
struct BoolExpr {
foo int
@ -37,7 +35,6 @@ struct UnaryExpr {
}
type Expr = Foo | BoolExpr | BinExpr | UnaryExpr
fn handle_expr(e Expr) {
@ -47,7 +44,7 @@ fn parse_bool() BoolExpr {
return BoolExpr{}
}
fn test_sum() {
fn test_sum_types() {
b := parse_bool()
handle_expr(b)
}