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:
@ -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 }')
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -15,7 +15,7 @@ const (
|
||||
error_context_after = 2 // ^^^ same, but after
|
||||
)
|
||||
|
||||
struct Scanner {
|
||||
pub struct Scanner {
|
||||
mut:
|
||||
file_path string
|
||||
text string
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Reference in New Issue
Block a user