v2: short struct init syntax; .xxx enum checks; unions; assert

pull/3853/head
Alexander Medvednikov 2020-02-26 15:51:05 +01:00
parent c26016b132
commit 857cbfb0d2
10 changed files with 128 additions and 67 deletions

View File

@ -2522,8 +2522,8 @@ fn (p mut Parser) indot_expr() string {
if is_map && typ != 'string' {
p.error('bad element type: expecting `string`')
}
T := p.table.find_type(arr_typ)
if !is_map && !T.has_method('contains') {
arr_typ2 := p.table.find_type(arr_typ)
if !is_map && !arr_typ2.has_method('contains') {
p.error('$arr_typ has no method `contains`')
}
// `typ` is element's type

View File

@ -109,7 +109,7 @@ int typ;
// Skip nameless enums
else if !no_name && !p.first_pass() {
p.cgen.typedefs << 'typedef int $enum_name;'
}
}
p.check(.rcbr)
p.fgen_nl()
p.fgen_nl()
@ -122,18 +122,18 @@ fn (p mut Parser) check_enum_member_access() {
if p.expected_type.starts_with('Option_') {
p.expected_type = p.expected_type[7..]
}
T := p.find_type(p.expected_type)
if T.cat == .enum_ {
tt := p.find_type(p.expected_type)
if tt.cat == .enum_ {
p.check(.dot)
val := p.check_name()
// Make sure this enum value exists
if !T.has_enum_val(val) {
p.error('enum `$T.name` does not have value `$val`')
if !tt.has_enum_val(val) {
p.error('enum `$tt.name` does not have value `$val`')
}
p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val)
p.gen(mod_gen_name(tt.mod) + '__' + p.expected_type + '_' + val)
}
else {
p.error('`$T.name` is not an enum')
p.error('`$tt.name` is not an enum')
}
}

View File

@ -675,8 +675,8 @@ fn (p mut Parser) expression() string {
return typ
}
fn (p mut Parser) handle_operator(op string, typ string, cpostfix string, ph int, T &Type) {
if T.has_method(op) {
fn (p mut Parser) handle_operator(op string, typ string,cpostfix string, ph int, tt &Type) {
if tt.has_method(op) {
p.cgen.set_placeholder(ph, '${typ}_${cpostfix}(')
p.gen(')')
}

View File

@ -1138,7 +1138,7 @@ fn (p mut Parser) fn_call_args(f mut Fn, generic_param_types []string) {
}
if i == 0 && (f.name == 'println' || f.name == 'print') && !(typ in ['string', 'ustring', 'void']) {
//
T := p.table.find_type(typ)
tt := p.table.find_type(typ)
$if !windows {
$if !js {
fmt := p.typ_to_fmt(typ, 0)
@ -1156,31 +1156,31 @@ fn (p mut Parser) fn_call_args(f mut Fn, generic_param_types []string) {
}
// Make sure this type has a `str()` method
$if !js {
if !T.has_method('str') {
if !tt.has_method('str') {
// varg
if T.name.starts_with('varg_') {
p.gen_varg_str(T)
if tt.name.starts_with('varg_') {
p.gen_varg_str(tt)
p.cgen.set_placeholder(ph, '${typ}_str(')
p.gen(')')
continue
}
// Arrays have automatic `str()` methods
else if T.name.starts_with('array_') {
p.gen_array_str(T)
else if tt.name.starts_with('array_') {
p.gen_array_str(tt)
p.cgen.set_placeholder(ph, '${typ}_str(')
p.gen(')')
continue
}
// struct
else if T.cat == .struct_ {
p.gen_struct_str(T)
else if tt.cat == .struct_ {
p.gen_struct_str(tt)
p.cgen.set_placeholder(ph, '${typ}_str(')
p.gen(')')
continue
}
else {
base := p.base_type(T.name)
if base != T.name {
base := p.base_type(tt.name)
if base != tt.name {
base_type := p.find_type(base)
if base_type.has_method('str') {
p.cgen.set_placeholder(ph, '${base_type.name}_str(')

View File

@ -1,6 +1,6 @@
/**********************************************************************
*
* f32 to string
* f32 to string
*
* Copyright (c) 2019-2020 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
@ -9,11 +9,11 @@
* This file contains the f32 to string functions
*
* These functions are based on the work of:
* Publication:PLDI 2018: Proceedings of the 39th ACM SIGPLAN
* Conference on Programming Language Design and ImplementationJune 2018
* Publication:PLDI 2018: Proceedings of the 39th ACM SIGPLAN
* Conference on Programming Language Design and ImplementationJune 2018
* Pages 270282 https://doi.org/10.1145/3192366.3192369
*
* inspired by the Go version here:
* inspired by the Go version here:
* https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
*
**********************************************************************/
@ -72,7 +72,7 @@ fn (d Dec32) get_string_32(neg bool, n_digit int) string {
mut x := 0
for x < (out_len-disp-1) {
buf[y - x] = `0` + byte(out%10)
out /= 10
out /= 10
i++
x++
}
@ -170,7 +170,7 @@ pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
mm_shift := bool_to_u32(mant != 0 || exp <= 1)
mm := u32(4 * m2 - 1 - mm_shift)
mut vr := u32(0)
mut vr := u32(0)
mut vp := u32(0)
mut vm := u32(0)
mut e10 := 0
@ -291,7 +291,7 @@ pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
out = vr + bool_to_u32(vr == vm || last_removed_digit >= 5)
}
return Dec32{m: out, e: e10 + removed}
return Dec32{m: out e: e10 + removed}
}
// f32_to_str return a string in scientific notation with max n_digit after the dot
@ -316,7 +316,7 @@ pub fn f32_to_str(f f32, n_digit int) string {
//println("with exp form")
d = f32_to_decimal(mant, exp)
}
//println("${d.m} ${d.e}")
return d.get_string_32(neg, n_digit)
}

View File

@ -28,7 +28,7 @@ powers_of_10 = [
// We only need to find the length of at most 17 digit numbers.
]
pow5_split_32 = [
pow5_split_32 = [
1152921504606846976, 1441151880758558720, 1801439850948198400, 2251799813685248000,
1407374883553280000, 1759218604441600000, 2199023255552000000, 1374389534720000000,
1717986918400000000, 2147483648000000000, 1342177280000000000, 1677721600000000000,
@ -55,8 +55,8 @@ pow5_inv_split_32 = [
]
pow5_split_64 =[
Uint128{u64(0), 72057594037927936},
Uint128{u64(0), 90071992547409920},
Uint128{0, 72057594037927936},
Uint128{0, 90071992547409920},
Uint128{u64(0), 112589990684262400},
Uint128{u64(0), 140737488355328000},
Uint128{u64(0), 87960930222080000},
@ -677,4 +677,4 @@ pow5_inv_split_64 = [
Uint128{8599192303405213841, 224711641857789488},
Uint128{14258051472207991719, 179769313486231590}
]
)
)

View File

@ -16,7 +16,7 @@ CastExpr | EnumVal | Assoc | SizeOf | None | MapInit
pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
LineComment | MultiLineComment
LineComment | MultiLineComment | AssertStmt
pub type Type = StructType | ArrayType
@ -469,6 +469,11 @@ pub:
expr Expr
}
pub struct AssertStmt {
pub:
expr Expr
}
pub struct Assoc {
pub:
name string

View File

@ -16,11 +16,12 @@ const (
)
pub struct Checker {
table &table.Table
table &table.Table
mut:
file ast.File
nr_errors int
errors []string
file ast.File
nr_errors int
errors []string
expected_type table.Type
}
pub fn new_checker(table &table.Table) Checker {
@ -78,6 +79,10 @@ pub fn (c mut Checker) check_struct_init(struct_init ast.StructInit) table.Type
}
.struct_ {
info := typ_sym.info as table.Struct
if struct_init.fields.len == 0 {
// Short syntax TODO check
return struct_init.typ
}
if struct_init.exprs.len > info.fields.len {
c.error('too many fields', struct_init.pos)
}
@ -279,6 +284,7 @@ pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type {
// The first element's type
if i == 0 {
elem_type = typ
c.expected_type = typ
continue
}
if !c.table.check(elem_type, typ) {
@ -366,15 +372,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
c.check_assign_expr(it)
}
ast.EnumVal {
typ_idx := c.table.find_type_idx(it.enum_name) // or {
typ := c.table.find_type(it.enum_name) or {
panic(err)
}
info := typ.info as table.Enum
if !(it.val in info.vals) {
c.error('enum `$it.enum_name` does not have a value `$it.val`', it.pos)
}
return typ_idx
return c.enum_val(it)
}
ast.FloatLiteral {
return table.f64_type
@ -651,6 +649,20 @@ pub fn (c mut Checker) index_expr(node ast.IndexExpr) table.Type {
return typ
}
// `.green` or `Color.green`
// If a short form is used, `expected_type` needs to be an enum
// with this value.
pub fn (c mut Checker) enum_val(node ast.EnumVal) table.Type {
typ_idx := if node.enum_name == '' { c.expected_type } else { c.table.find_type_idx(node.enum_name) }
typ := c.table.get_type_symbol(table.Type(typ_idx))
// println('checker: enum val $c.expected_type $typ.name')
info := typ.info as table.Enum
if !(node.val in info.vals) {
c.error('enum `$typ.name` does not have a value `$node.val`', node.pos)
}
return typ_idx
}
pub fn (c mut Checker) error(s string, pos token.Position) {
c.nr_errors++
print_backtrace()

View File

@ -238,6 +238,9 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
.key_enum {
return p.enum_decl()
}
.key_union {
return p.struct_decl()
}
.line_comment {
// p.next()
return ast.LineComment{
@ -252,7 +255,7 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
}
else {
// #printf("");
p.error('parser: bad top level statement')
p.error('parser: bad top level statement ' + p.tok.str())
return ast.Stmt{}
}
}
@ -260,6 +263,13 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
pub fn (p mut Parser) stmt() ast.Stmt {
match p.tok.kind {
.key_assert {
p.next()
expr,_ := p.expr(0)
return ast.AssertStmt{
expr: expr
}
}
.key_mut {
return p.var_decl()
}
@ -481,7 +491,7 @@ fn (p mut Parser) struct_init() ast.StructInit {
mut field_names := []string
mut exprs := []ast.Expr
mut i := 0
// TODO if sym.info is table.Struct
// TODO `if sym.info is table.Struct`
mut is_struct := false
match sym.info {
table.Struct {
@ -489,25 +499,41 @@ fn (p mut Parser) struct_init() ast.StructInit {
}
else {}
}
is_short_syntax := !(p.peek_tok.kind == .colon || p.tok.kind == .rcbr) // `Vec{a,b,c}`
// p.warn(is_short_syntax.str())
for p.tok.kind != .rcbr {
field_name := p.check_name()
field_names << field_name
mut field_name := ''
if is_short_syntax {
expr,_ := p.expr(0)
exprs << expr
}
else {
field_name = p.check_name()
field_names << field_name
}
// Set expected type for this field's expression
// p.warn('$sym.name field $field_name')
if is_struct {
info := sym.info as table.Struct
field := sym.find_field(field_name) or {
p.error('field `${sym.name}.$field_name` not found')
continue
if is_short_syntax {}
else {
field := sym.find_field(field_name) or {
p.error('field `${sym.name}.$field_name` not found')
continue
}
p.expected_type = field.typ
}
p.expected_type = field.typ
// p.warn('setting exp $field.typ')
}
//
p.check(.colon)
expr,_ := p.expr(0)
exprs << expr
if !is_short_syntax {
p.check(.colon)
expr,_ := p.expr(0)
exprs << expr
}
i++
if p.tok.kind == .comma {
p.check(.comma)
}
}
node := ast.StructInit{
typ: typ
@ -609,7 +635,8 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
}
.dot {
// .enum_val
node,typ = p.enum_val()
// node,typ = p.enum_val()
node = p.enum_val()
}
.chartoken {
typ = table.byte_type
@ -909,14 +936,25 @@ fn (p &Parser) is_addative() bool {
*/
// `.green`
// `pref.BuildMode.default_mode`
fn (p mut Parser) enum_val() (ast.Expr,table.Type) {
fn (p mut Parser) enum_val() ast.EnumVal {
p.check(.dot)
val := p.check_name()
mut node := ast.Expr{}
node = ast.EnumVal{
/*
if p.expected_type == 0 {
p.error('wtf')
}
*/
/*
sym := p.table.get_type_symbol(p.expected_type) //or {
//return ast.EnumVal{val:val}
//}
p.warn(sym.name)
*/
return ast.EnumVal{
val: val
}
return node,table.int_type
}
fn (p mut Parser) for_statement() ast.Stmt {
@ -1332,12 +1370,18 @@ fn (p mut Parser) const_decl() ast.ConstDecl {
}
}
// structs and unions
fn (p mut Parser) struct_decl() ast.StructDecl {
is_pub := p.tok.kind == .key_pub
if is_pub {
p.next()
}
p.check(.key_struct)
if p.tok.kind == .key_struct {
p.check(.key_struct)
}
else {
p.check(.key_union)
}
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
if is_c {
p.next() // C

View File

@ -56,7 +56,7 @@ pub fn (t mut Table) register_global(name string, typ Type) {
// mod: p.mod
// is_mut: true
// idx: -1
}
}
@ -186,7 +186,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
return &t.types[idx]
}
// this should never happen
panic('get_type_symbol: invalid type $typ - $idx')
panic('get_type_symbol: invalid type $typ - ${idx}. This should neer happen')
}
// this will override or register builtin type