v2: consts, $if, attributes, globals, if/for type check, prefs

pull/3635/head
Alexander Medvednikov 2020-02-03 07:02:54 +01:00
parent 7808f4c272
commit d87cb3f672
11 changed files with 433 additions and 159 deletions

View File

@ -81,10 +81,10 @@ pub fn eprintln(s string) {
panic('eprintln(NIL)')
}
$if !windows {
C.fflush(stdout)
C.fflush(stderr)
C.fprintf(stderr, '%.*s\n', s.len, s.str)
C.fflush(stderr)
C.fflush(C.stdout)
C.fflush(C.stderr)
C.fprintf(C.stderr, '%.*s\n', s.len, s.str)
C.fflush(C.stderr)
return
}
// TODO issues with stderr and cross compiling for Linux
@ -96,10 +96,10 @@ pub fn eprint(s string) {
panic('eprint(NIL)')
}
$if !windows {
C.fflush(stdout)
C.fflush(stderr)
C.fprintf(stderr, '%.*s', s.len, s.str)
C.fflush(stderr)
C.fflush(C.stdout)
C.fflush(C.stderr)
C.fprintf(C.stderr, '%.*s', s.len, s.str)
C.fflush(C.stderr)
return
}
print(s)
@ -124,6 +124,8 @@ pub fn print(s string) {
__global total_m i64=0
__global nr_mallocs int=0
fn looo(){} // TODO remove, [ pratt
[unsafe_fn]
pub fn malloc(n int) byteptr {
if n <= 0 {

View File

@ -8,12 +8,12 @@ import (
v.table
)
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral |
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral |
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr
pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt |
ForStmt | StructDecl | ForCStmt | ForInStmt
pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr
// | IncDecStmt k
// Stand-alone expression in a statement list.
pub struct ExprStmt {
@ -63,7 +63,13 @@ pub struct Field {
pub:
name string
// type_idx int
ti table.Type
typ table.Type
}
pub struct ConstDecl {
pub:
fields []Field
exprs []Expr
}
pub struct StructDecl {
@ -159,6 +165,14 @@ mut:
pos token.Position
}
pub struct GlobalDecl {
pub:
name string
expr Expr
mut:
typ table.Type
}
pub struct File {
pub:
mod Module
@ -178,6 +192,7 @@ type IdentInfo = IdentVar
pub enum IdentKind {
blank_ident
variable
constant
}
// A single identifier
@ -232,6 +247,7 @@ pub:
// op token.Kind
left Expr
index Expr // [0], [start..end] etc
typ table.Type
}
pub struct IfExpr {
@ -242,12 +258,21 @@ pub:
else_stmts []Stmt
ti table.Type
left Expr // `a` in `a := if ...`
pos token.Position
}
pub struct CompIf {
pub:
cond Expr
stmts []Stmt
else_stmts []Stmt
}
pub struct ForStmt {
pub:
cond Expr
stmts []Stmt
pos token.Position
}
pub struct ForInStmt {
@ -280,6 +305,11 @@ pub:
}
*/
// e.g. `[unsafe_fn]`
pub struct Attr {
pub:
name string
}
pub struct AssignExpr {
pub:

View File

@ -68,6 +68,9 @@ pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.Type {
// c.error('infix expr: cannot use `$infix_expr.right_type.name` as `$infix_expr.left_type.name`', infix_expr.pos)
c.error('infix expr: cannot use `$left_ti.name` as `$right_ti.name`', infix_expr.pos)
}
if infix_expr.op.is_relational() {
return table.bool_type
}
return left_ti
}
@ -195,111 +198,120 @@ fn (c &Checker) stmt(node ast.Stmt) {
ast.VarDecl {
typ := c.expr(it.expr)
// println('var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr')
if it.typ.kind == .unresolved {
// it.ti = typ
// println('unresolved var')
}
// if it.typ.kind == .unresolved {
// it.ti = typ
// println('unresolved var')
// }
}
ast.ForStmt {
typ := c.expr(it.cond)
if typ.kind != .bool {
c.error('non-bool used as for condition', it.pos)
}
ast.ForStmt {
c.expr(it.cond)
for stmt in it.stmts {
c.stmt(stmt)
}
for stmt in it.stmts {
c.stmt(stmt)
}
ast.ForCStmt {
c.stmt(it.init)
c.expr(it.cond)
c.stmt(it.inc)
for stmt in it.stmts {
c.stmt(stmt)
}
}
ast.ForCStmt {
c.stmt(it.init)
c.expr(it.cond)
c.stmt(it.inc)
for stmt in it.stmts {
c.stmt(stmt)
}
// ast.StructDecl {}
ast.ExprStmt {
c.expr(it.expr)
}
else {}
}
}
// ast.StructDecl {}
ast.ExprStmt {
c.expr(it.expr)
}
else {}
}
}
pub fn (c &Checker) expr(node ast.Expr) table.Type {
match node {
ast.AssignExpr {
c.check_assign_expr(it)
}
ast.IntegerLiteral {
return table.int_type
}
// ast.FloatLiteral {}
ast.PostfixExpr {
return c.expr(it.expr)
}
/*
pub fn (c &Checker) expr(node ast.Expr) table.Type {
match node {
ast.AssignExpr {
c.check_assign_expr(it)
}
ast.IntegerLiteral {
return table.int_type
}
// ast.FloatLiteral {}
ast.PostfixExpr {
return c.expr(it.expr)
}
/*
ast.UnaryExpr {
c.expr(it.left)
}
*/
ast.StringLiteral {
return table.string_type
}
ast.PrefixExpr {
return c.expr(it.right)
}
ast.InfixExpr {
return c.infix_expr(it)
}
ast.StructInit {
return c.check_struct_init(it)
}
ast.CallExpr {
return c.call_expr(it)
}
ast.MethodCallExpr {
return c.check_method_call_expr(it)
}
ast.ArrayInit {
return c.array_init(it)
}
ast.Ident {
if it.kind == .variable {
info := it.info as ast.IdentVar
if info.typ.kind != .unresolved {
return info.typ
}
return c.expr(info.expr)
ast.StringLiteral {
return table.string_type
}
ast.PrefixExpr {
return c.expr(it.right)
}
ast.InfixExpr {
return c.infix_expr(it)
}
ast.StructInit {
return c.check_struct_init(it)
}
ast.CallExpr {
return c.call_expr(it)
}
ast.MethodCallExpr {
return c.check_method_call_expr(it)
}
ast.ArrayInit {
return c.array_init(it)
}
ast.Ident {
if it.kind == .variable {
info := it.info as ast.IdentVar
if info.typ.kind != .unresolved {
return info.typ
}
return table.void_type
return c.expr(info.expr)
}
// ast.BoolLiteral {}
ast.SelectorExpr {
return c.selector_expr(it)
return table.void_type
}
ast.BoolLiteral {
return table.bool_type
}
ast.SelectorExpr {
return c.selector_expr(it)
}
ast.IndexExpr {
// c.expr(it.left)
// c.expr(it.index)
return it.typ
}
ast.IfExpr {
typ := c.expr(it.cond)
if typ.kind != .bool {
c.error('non-bool (`$typ.name`) used as if condition', it.pos)
}
ast.IndexExpr {
c.expr(it.left)
c.expr(it.index)
for i, stmt in it.stmts {
c.stmt(stmt)
}
ast.IfExpr {
c.expr(it.cond)
for i, stmt in it.stmts {
if it.else_stmts.len > 0 {
for stmt in it.else_stmts {
c.stmt(stmt)
}
if it.else_stmts.len > 0 {
for stmt in it.else_stmts {
c.stmt(stmt)
}
}
}
else {}
}
return table.void_type
}
else {}
}
return table.void_type
}
pub fn (c &Checker) error(s string, pos token.Position) {
print_backtrace()
final_msg_line := '$c.file_name:$pos.line_nr: error: $s'
eprintln(final_msg_line)
/*
pub fn (c &Checker) error(s string, pos token.Position) {
print_backtrace()
final_msg_line := '$c.file_name:$pos.line_nr: error: $s'
eprintln(final_msg_line)
/*
if colored_output {
eprintln(term.bold(term.red(final_msg_line)))
}else{
@ -307,5 +319,5 @@ fn (c &Checker) stmt(node ast.Stmt) {
}
*/
exit(1)
}
exit(1)
}

View File

@ -51,6 +51,13 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// g.writeln('//// stmt start')
match node {
ast.Import {}
ast.ConstDecl {
for i, field in it.fields {
g.write('$field.typ.name $field.name = ')
g.expr(it.exprs[i])
g.writeln(';')
}
}
ast.FnDecl {
g.fn_decl = &it
is_main := it.name == 'main'
@ -145,7 +152,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln('typedef struct {')
for field in it.fields {
// t := g.table.get_type(field.ti.idx)
ti := g.table.refresh_ti(field.ti)
ti := g.table.refresh_ti(field.typ)
g.writeln('\t$ti.name $field.name;')
}
g.writeln('} $it.name;')

View File

@ -6,6 +6,8 @@ multi_return_int_string multi_return();
void variadic(variadic_int a);
void ensure_cap(int required, int cap);
int pi = 3;
typedef struct {
int age;
} User;
@ -19,6 +21,7 @@ int main() {
a++;
foo(3);
int ak = 10;
int mypi = pi;
return 0;
}

View File

@ -1,6 +1,12 @@
import moda
import modb as mb
const (
pi = 3
//s = 'hi'
)
struct User {
age int
}
@ -15,6 +21,7 @@ fn main() {
a++
foo(3)
ak := 10
mypi := pi
}
/*
user := User{}

View File

@ -50,7 +50,7 @@ pub fn (p mut Parser) call_args() []ast.Expr {
return args // ,table.void_ti
}
fn (p mut Parser) fn_decl() ast.FnDecl {
fn (p mut Parser) fn_decl(/*high bool*/) ast.FnDecl {
is_pub := p.tok.kind == .key_pub
if is_pub {
p.next()
@ -68,14 +68,18 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .key_mut {
p.next()
}
rec_ti = p.parse_ti()
rec_ti = p.parse_type()
p.table.register_var(table.Var{
name: rec_name
typ: rec_ti
})
p.check(.rpar)
}
name := p.check_name()
mut name := ''
if p.tok.kind == .name {
// TODO
name = p.check_name()
}
// println('fn decl $name')
p.check(.lpar)
// Args
@ -88,7 +92,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.check(.comma)
arg_names << p.check_name()
}
ti := p.parse_ti()
ti := p.parse_type()
for arg_name in arg_names {
arg := table.Var{
name: arg_name
@ -112,7 +116,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
// Return type
mut typ := table.void_type
if p.tok.kind in [.name, .lpar] {
typ = p.parse_ti()
typ = p.parse_type()
p.return_type = typ
}
else {
@ -144,7 +148,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
is_pub: is_pub
receiver: ast.Field{
name: rec_name
ti: rec_ti
typ: rec_ti
}
}
}

View File

@ -13,13 +13,13 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type {
if p.tok.kind == .number {
size := p.tok.lit.int()
p.check(.rsbr)
elem_ti := p.parse_ti()
elem_ti := p.parse_type()
idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1)
return table.new_type(.array_fixed, name, idx, nr_muls)
}
// array
p.check(.rsbr)
elem_ti := p.parse_ti()
elem_ti := p.parse_type()
mut nr_dims := 1
for p.tok.kind == .lsbr {
p.check(.lsbr)
@ -33,9 +33,9 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type {
pub fn (p mut Parser) parse_map_ti(nr_muls int) table.Type {
p.next()
p.check(.lsbr)
key_ti := p.parse_ti()
key_ti := p.parse_type()
p.check(.rsbr)
value_ti := p.parse_ti()
value_ti := p.parse_type()
idx,name := p.table.find_or_register_map(&key_ti, &value_ti)
return table.new_type(.map, name, idx, nr_muls)
}
@ -44,7 +44,7 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type {
p.check(.lpar)
mut mr_tis := []table.Type
for {
mr_ti := p.parse_ti()
mr_ti := p.parse_type()
mr_tis << mr_ti
if p.tok.kind == .comma {
p.check(.comma)
@ -60,12 +60,18 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type {
pub fn (p mut Parser) parse_variadic_ti() table.Type {
p.check(.ellipsis)
variadic_ti := p.parse_ti()
variadic_ti := p.parse_type()
idx,name := p.table.find_or_register_variadic(&variadic_ti)
return table.new_type(.variadic, name, idx, 0)
}
pub fn (p mut Parser) parse_ti() table.Type {
pub fn (p mut Parser) parse_fn_type() table.Type {
//p.check(.key_fn)
p.fn_decl()
return table.int_type
}
pub fn (p mut Parser) parse_type() table.Type {
mut nr_muls := 0
for p.tok.kind == .amp {
p.check(.amp)
@ -73,6 +79,10 @@ pub fn (p mut Parser) parse_ti() table.Type {
}
name := p.tok.lit
match p.tok.kind {
// func
.key_fn {
return p.parse_fn_type()
}
// array
.lsbr {
return p.parse_array_ti(nr_muls)

View File

@ -8,6 +8,7 @@ import (
v.ast
v.token
v.table
v.pref
term
os
)
@ -35,6 +36,9 @@ mut:
//
// prefix_parse_fns []PrefixParseFn
inside_if bool
pref &pref.Preferences // Preferences shared from V struct
builtin_mod bool
mod string
}
// for tests
@ -59,6 +63,8 @@ pub fn parse_file(path string, table &table.Table) ast.File {
scanner: scanner.new_scanner(text)
table: table
file_name: path
pref: &pref.Preferences{}
builtin_mod: true
}
p.read_first_token()
// module decl
@ -170,6 +176,12 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
// }
}
}
.lsbr {
return p.attr()
}
.key_global {
return p.global_decl()
}
.key_const {
return p.const_decl()
}
@ -179,16 +191,12 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
.key_struct {
return p.struct_decl()
}
.lsbr {
p.next()
p.check(.name)
p.check(.rsbr)
return ast.Module{}
.dollar {
return p.comp_if()
}
else {
p.error('bad top level statement')
return ast.Module{} // silence C warning
// exit(0)
return ast.Stmt{}
}
}
}
@ -204,6 +212,9 @@ pub fn (p mut Parser) stmt() ast.Stmt {
.key_return {
return p.return_stmt()
}
.dollar {
return p.comp_if()
}
else {
// `x := ...`
if p.tok.kind == .name && p.peek_tok.kind == .decl_assign {
@ -218,6 +229,22 @@ pub fn (p mut Parser) stmt() ast.Stmt {
}
}
pub fn (p mut Parser) comp_if() ast.CompIf {
p.next()
p.check(.key_if)
if p.tok.kind == .not {
p.next()
}
p.check_name()
p.parse_block()
if p.tok.kind == .dollar && p.peek_tok.kind == .key_else {
p.next()
p.check(.key_else)
p.parse_block()
}
return ast.CompIf{}
}
pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr {
op := p.tok.kind
p.next()
@ -231,6 +258,15 @@ pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr {
return node
}
fn (p mut Parser) attr() ast.Attr {
p.check(.lsbr)
name := p.check_name()
p.check(.rsbr)
return ast.Attr{
name: name
}
}
fn (p mut Parser) range_expr(low ast.Expr) ast.Expr {
// ,table.Type) {
p.next()
@ -310,7 +346,8 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
mut node := ast.Expr{}
// mut typ := table.void_ti
mut typ := table.unresolved_type
if p.tok.lit == 'C' {
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
if is_c {
p.next()
p.check(.dot)
}
@ -327,7 +364,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
}
// struct init
else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || p.tok.lit in ['array', 'string']) {
typ = p.parse_ti()
typ = p.parse_type()
// p.warn('struct init typ=$typ.name')
p.check(.lcbr)
mut field_names := []string
@ -347,13 +384,13 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
}
p.check(.rcbr)
}
// variable
else {
// p.warn('name ')
// left := p.parse_ident()
mut ident := ast.Ident{
name: p.tok.lit
}
// variable
if var := p.table.find_var(p.tok.lit) {
typ = var.typ
ident.kind = .variable
@ -361,18 +398,40 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
typ: typ
name: ident.name
// expr: p.expr(0)// var.expr
}
// ident.ti = ti
node = ident
p.next()
}else{
// Function object (not a call), e.g. `onclick(my_click)`
p.table.find_fn(p.tok.lit) or {
p.error('name expr unknown variable `$p.tok.lit`')
exit(0)
if is_c {
typ = table.int_type
ident.info = ast.IdentVar{
typ: typ
name: ident.name
}
node = ident
p.next()
return node,typ
}
// const
if c := p.table.find_const(p.tok.lit) {
typ = c.typ
ident.kind = .constant
ident.info = ast.IdentVar{
typ: typ
name: ident.name
}
node = ident
p.next()
}else{
// Function object (not a call), e.g. `onclick(my_click)`
p.table.find_fn(p.tok.lit) or {
p.error('name expr unknown identifier `$p.tok.lit`')
exit(0)
}
p.next()
}
p.next()
}
}
return node,typ
@ -505,6 +564,7 @@ fn (p mut Parser) index_expr(left ast.Expr, typ_ table.Type) (ast.Expr,table.Typ
node = ast.IndexExpr{
left: left
index: index_expr
typ: typ
}
// return node
return node,typ
@ -572,6 +632,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
stmts := p.parse_block()
return ast.ForStmt{
stmts: stmts
pos: p.tok.position()
}
}
else if p.tok.kind == .key_mut {
@ -600,9 +661,6 @@ fn (p mut Parser) for_statement() ast.Stmt {
if p.tok.kind != .semicolon {
mut typ := table.Type{}
cond,typ = p.expr(0)
if typ.kind != .bool {
p.error('non-bool used as for condition')
}
}
p.check(.semicolon)
if p.tok.kind != .lcbr {
@ -630,6 +688,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
// println('nr stmts=$stmts.len')
return ast.ForStmt{
stmts: stmts
pos: p.tok.position()
}
}
// `for cond {`
@ -641,6 +700,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
return ast.ForStmt{
cond: cond
stmts: stmts
pos: p.tok.position()
}
}
@ -650,12 +710,8 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
// }
mut node := ast.Expr{}
p.check(.key_if)
cond,cond_ti := p.expr(0)
cond,_ := p.expr(0)
p.inside_if = false
// if !p.table.check(table.bool_ti, cond_ti) {
if cond_ti.kind != .bool {
p.error('non-bool (`$cond_ti.name`) used as if condition')
}
stmts := p.parse_block()
mut else_stmts := []ast.Stmt
if p.tok.kind == .key_else {
@ -679,8 +735,9 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
stmts: stmts
else_stmts: else_stmts
ti: ti
pos: p.tok.position()
// left: left
}
return node,ti
}
@ -708,19 +765,19 @@ fn (p mut Parser) string_expr() (ast.Expr,table.Type) {
fn (p mut Parser) array_init() (ast.Expr,table.Type) {
p.check(.lsbr)
mut val_ti := table.void_type
mut val_type := table.void_type
mut exprs := []ast.Expr
for i := 0; p.tok.kind != .rsbr; i++ {
expr,ti := p.expr(0)
expr,typ := p.expr(0)
exprs << expr
if i == 0 {
val_ti = ti
val_type = typ
}
if p.tok.kind == .comma {
p.check(.comma)
}
}
type_idx,type_name := p.table.find_or_register_array(val_ti, 1)
type_idx,type_name := p.table.find_or_register_array(val_type, 1)
array_ti := table.new_type(.array, type_name, type_idx, 0)
mut node := ast.Expr{}
node = ast.ArrayInit{
@ -792,20 +849,31 @@ fn (p mut Parser) import_stmt() []ast.Import {
return imports
}
// TODO
// fn (p mut Parser) const_decl() ast... {
fn (p mut Parser) const_decl() ast.Stmt {
fn (p mut Parser) const_decl() ast.ConstDecl {
p.check(.key_const)
p.check(.lpar)
mut fields := []ast.Field
mut exprs := []ast.Expr
for p.tok.kind != .rpar {
name := p.check_name()
println('const: $name')
p.check(.assign)
_,_ := p.expr(0)
// expr, ti := p.expr(0)
expr,typ := p.expr(0)
fields << ast.Field{
name: name
typ: typ
}
exprs << expr
p.table.register_const(table.Var{
name: name
typ: typ
})
}
p.check(.rpar)
return ast.Stmt{}
return ast.ConstDecl{
fields: fields
exprs: exprs
}
}
fn (p mut Parser) struct_decl() ast.StructDecl {
@ -824,15 +892,15 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
p.check(.colon)
}
field_name := p.check_name()
ti := p.parse_ti()
ti := p.parse_type()
ast_fields << ast.Field{
name: field_name
ti: ti
typ: ti
}
fields << table.Field{
name: field_name
// type_idx: ti.idx
ti: ti
}
}
@ -905,7 +973,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
name: name
is_mut: is_mut
// expr: expr
typ: typ
})
p.warn('var decl name=$name typ=$typ.name')
@ -913,7 +981,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
node := ast.VarDecl{
name: name
expr: expr // p.expr(token.lowest_prec)
is_mut: is_mut
typ: typ
pos: p.tok.position()
@ -921,6 +989,40 @@ fn (p mut Parser) var_decl() ast.VarDecl {
return node
}
fn (p mut Parser) global_decl() ast.GlobalDecl {
if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
p.error('use `v --enable-globals ...` to enable globals')
}
p.next()
name := p.check_name()
println(name)
typ := p.parse_type()
if p.tok.kind == .assign {
p.next()
p.expr(0)
}
p.table.register_global(name, typ)
// p.genln(p.table.cgen_name_type_pair(name, typ))
/*
mut g := p.table.cgen_name_type_pair(name, typ)
if p.tok == .assign {
p.next()
g += ' = '
_,expr := p.tmp_expr()
g += expr
}
// p.genln('; // global')
g += '; // global'
if !p.cgen.nogen {
p.cgen.consts << g
}
*/
return ast.GlobalDecl{
name: name
}
}
fn verror(s string) {
println(s)
exit(1)

68
vlib/v/pref/pref.v 100644
View File

@ -0,0 +1,68 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module pref
pub enum BuildMode {
// `v program.v'
// Build user code only, and add pre-compiled vlib (`cc program.o builtin.o os.o...`)
default_mode
// `v -lib ~/v/os`
// build any module (generate os.o + os.vh)
build_module
}
pub struct Preferences {
pub mut:
build_mode BuildMode
// nofmt bool // disable vfmt
is_test bool // `v test string_test.v`
is_script bool // single file mode (`v program.v`), main function can be skipped
is_live bool // main program that contains live/hot code
is_solive bool // a shared library, that will be used in a -live main program
is_so bool // an ordinary shared library, -shared, no matter if it is live or not
is_prof bool // benchmark every function
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
is_prod bool // use "-O2"
is_verbose bool // print extra information with `v.log()`
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
is_repl bool
is_run bool
show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c
sanitize bool // use Clang's new "-fsanitize" option
is_debug bool // false by default, turned on by -g or -cg, it tells v to pass -g to the C backend compiler.
is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly).
is_keep_c bool // -keep_c , tell v to leave the generated .tmp.c alone (since by default v will delete them after c backend finishes)
// NB: passing -cg instead of -g will set is_vlines to false and is_g to true, thus making v generate cleaner C files,
// which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks).
is_pretty_c bool // -pretty_c , tell v to run clang-format -i over the produced C file, before it is compiled. Use with -keep_c or with -o x.c .
is_cache bool // turns on v usage of the module cache to speed up compilation.
is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run
no_auto_free bool // `v -nofree` disable automatic `free()` insertion for better performance in some applications (e.g. compilers)
cflags string // Additional options which will be passed to the C compiler.
// For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size.
// You could pass several -cflags XXX arguments. They will be merged with each other.
// You can also quote several options at the same time: -cflags '-Os -fno-inline-small-functions'.
ccompiler string // the name of the used C compiler
building_v bool
autofree bool
compress bool
// skip_builtin bool // Skips re-compilation of the builtin module
// to increase compilation time.
// This is on by default, since a vast majority of users do not
// work on the builtin module itself.
// generating_vh bool
fast bool // use tcc/x64 codegen
enable_globals bool // allow __global for low level code
// is_fmt bool
is_bare bool
user_mod_path string // `v -user_mod_path /Users/user/modules` adds a new lookup path for imported modules
vlib_path string
vpath string
x64 bool
output_cross_c bool
prealloc bool
v2 bool
}

View File

@ -14,6 +14,7 @@ pub mut:
local_vars []Var
// fns Hashmap
fns map[string]Fn
consts map[string]Var
tmp_cnt int
imports []string
}
@ -27,11 +28,13 @@ pub:
pub struct Var {
pub:
name string
is_mut bool
name string
is_mut bool
is_const bool
is_global bool
// expr ast.Expr
mut:
typ Type
typ Type
}
pub fn new_table() &Table {
@ -78,6 +81,23 @@ pub fn (t mut Table) clear_vars() {
}
}
pub fn (t mut Table) register_const(v Var) {
t.consts[v.name] = v
}
pub fn (t mut Table) register_global(name string, typ Type) {
t.consts[name] = Var{
name: name
typ: typ
is_const: true
is_global: true
// mod: p.mod
// is_mut: true
// idx: -1
}
}
pub fn (t mut Table) register_var(v Var) {
println('register_var: $v.name - $v.typ.name')
t.local_vars << v
@ -112,6 +132,15 @@ pub fn (t &Table) find_fn(name string) ?Fn {
return none
}
pub fn (t &Table) find_const(name string) ?Var {
f := t.consts[name]
if f.name.str != 0 {
// TODO
return f
}
return none
}
pub fn (t mut Table) register_fn(new_fn Fn) {
// println('reg fn $new_fn.name nr_args=$new_fn.args.len')
t.fns[new_fn.name] = new_fn
@ -351,7 +380,7 @@ pub fn (t &Table) check(got, expected &Type) bool {
// if expected.name == 'array' {
// return true
// }
if got.idx != expected.idx {
if got.idx != expected.idx && got.name != expected.name {
return false
}
return true