all: mutability check (part 1); enable mutable sumtype args

pull/6449/head
Alexander Medvednikov 2020-09-22 05:28:29 +02:00
parent 1ee0939f69
commit 624f22e27e
12 changed files with 122 additions and 125 deletions

View File

@ -145,7 +145,7 @@ pub fn (a array) repeat(count int) array {
// array.sort sorts array in-place using given `compare` function as comparator
pub fn (mut a array) sort_with_compare(compare voidptr) {
C.qsort(a.data, a.len, a.element_size, compare)
C.qsort(mut a.data, a.len, a.element_size, compare)
}
// array.insert

View File

@ -274,7 +274,7 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
e10 = int(q) + e2
i := -e2 - int(q)
k := pow5_bits(i) - pow5_num_bits_64
mut j := int(q) - k
j := int(q) - k
mul := pow5_split_64[i]
vr = mul_shift_64(u64(4) * m2 , mul, j)
vp = mul_shift_64(u64(4) * m2 + u64(2) , mul, j)

View File

@ -472,7 +472,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
}
// single char, manage it here
if ch == `c` && status == .field_char {
if ch == `c` && status == .field_char {
v_sprintf_panic(p_index, pt.len)
d1 := unsafe {*(&byte(pt[p_index]))}
res.write_b(d1)
@ -777,7 +777,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
if ch in [`f`, `F`] {
v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&f64(pt[p_index]))}
mut positive := x >= f64(0.0)
positive := x >= f64(0.0)
len1 = if len1 >= 0 { len1 } else { def_len1 }
s := format_fl(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign})
res.write(if ch == `F` {s.to_upper()} else {s})
@ -789,7 +789,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
else if ch in [`e`, `E`] {
v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&f64(pt[p_index]))}
mut positive := x >= f64(0.0)
positive := x >= f64(0.0)
len1 = if len1 >= 0 { len1 } else { def_len1 }
s := format_es(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign})
res.write(if ch == `E` {s.to_upper()} else {s})
@ -801,7 +801,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
else if ch in [`g`, `G`] {
v_sprintf_panic(p_index, pt.len)
x := unsafe {*(&f64(pt[p_index]))}
mut positive := x >= f64(0.0)
positive := x >= f64(0.0)
mut s := ""
tx := fabs(x)
if tx < 999_999.0 && tx >= 0.00001 {
@ -844,11 +844,11 @@ pub fn v_sprintf(str string, pt ... voidptr) string{
return res.str()
}
[inline]
[inline]
fn v_sprintf_panic( idx, len int) {
if idx >= len {
panic('${idx+1} % conversion specifiers, but given only ${len} args')
}
}
}
fn fabs(x f64) f64 {

View File

@ -55,17 +55,17 @@ pub fn parse_rfc2822(s string) ?Time {
// also checks and support for leapseconds should be added in future PR
pub fn parse_iso8601(s string) ?Time {
mut year := 0
mut month := 0
mut day := 0
mut hour := 0
mut minute := 0
mut second := 0
mut mic_second := 0
mut time_char := `a`
mut plus_min := `a`
mut offset_hour := 0
mut offset_min := 0
year := 0
month := 0
day := 0
hour := 0
minute := 0
second := 0
mic_second := 0
time_char := `a`
plus_min := `a`
offset_hour := 0
offset_min := 0
count := unsafe {C.sscanf(charptr(s.str), "%4d-%2d-%2d%c%2d:%2d:%2d.%6d%c%2d:%2d", &year, &month, &day,
&time_char, &hour, &minute,

View File

@ -12,9 +12,9 @@ pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr |
ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral |
Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr |
MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectExpr |
SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit | Type |
TypeOf | UnsafeExpr
MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr |
SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit |
Type | TypeOf | UnsafeExpr
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
@ -491,8 +491,8 @@ pub mut:
pub struct UnsafeExpr {
pub:
expr Expr
pos token.Position
expr Expr
pos token.Position
}
pub struct LockExpr {
@ -966,7 +966,8 @@ pub fn (expr Expr) is_blank_ident() bool {
pub fn (expr Expr) position() token.Position {
// all uncommented have to be implemented
match mut expr {
match expr {
// KEKW2
AnonFn {
return expr.decl.pos
}
@ -1084,8 +1085,8 @@ pub fn (expr Expr) is_lvalue() bool {
pub fn (expr Expr) is_expr() bool {
match expr {
IfExpr {return expr.is_expr}
MatchExpr {return expr.is_expr}
IfExpr { return expr.is_expr }
MatchExpr { return expr.is_expr }
else {}
}
return true
@ -1151,16 +1152,12 @@ pub fn (stmt Stmt) position() token.Position {
// field table.Field.default_expr, which should be ast.Expr
pub fn fe2ex(x table.FExpr) Expr {
res := Expr{}
unsafe {
C.memcpy(&res, &x, sizeof(Expr))
}
unsafe {C.memcpy(&res, &x, sizeof(Expr))}
return res
}
pub fn ex2fe(x Expr) table.FExpr {
res := table.FExpr{}
unsafe {
C.memcpy(&res, &x, sizeof(table.FExpr))
}
unsafe {C.memcpy(&res, &x, sizeof(table.FExpr))}
return res
}

View File

@ -37,8 +37,7 @@ pub fn (s &Scope) find_with_scope(name string) ?(ScopeObject, &Scope) {
}
pub fn (s &Scope) find(name string) ?ScopeObject {
for sc := s; true; sc = sc.parent
{
for sc := s; true; sc = sc.parent {
if name in sc.objects {
return sc.objects[name]
}
@ -85,6 +84,7 @@ pub fn (s &Scope) known_var(name string) bool {
}
pub fn (mut s Scope) update_var_type(name string, typ table.Type) {
s.end_pos = s.end_pos // TODO mut bug
match mut s.objects[name] {
Var {
if it.typ == typ {

View File

@ -13,17 +13,12 @@ pub fn (node &FnDecl) modname() string {
}
mut pamod := node.name.all_before_last('.')
if pamod == node.name.after('.') {
pamod = if node.is_builtin {
'builtin'
} else {
'main'
}
pamod = if node.is_builtin { 'builtin' } else { 'main' }
}
return pamod
}
// These methods are used only by vfmt, vdoc, and for debugging.
pub fn (node &FnDecl) stringify(t &table.Table, cur_mod string) string {
mut f := strings.new_builder(30)
if node.is_pub {
@ -32,7 +27,7 @@ pub fn (node &FnDecl) stringify(t &table.Table, cur_mod string) string {
mut receiver := ''
if node.is_method {
mut styp := util.no_cur_mod(t.type_to_str(node.receiver.typ), cur_mod)
mut m := if node.rec_mut { node.receiver.typ.share().str() + ' ' } else { '' }
m := if node.rec_mut { node.receiver.typ.share().str() + ' ' } else { '' }
if node.rec_mut {
styp = styp[1..] // remove &
}
@ -51,11 +46,10 @@ pub fn (node &FnDecl) stringify(t &table.Table, cur_mod string) string {
mut name := if node.is_anon { '' } else { node.name.after('.') }
if node.language == .c {
name = 'C.$name'
}
else if node.language == .js {
} else if node.language == .js {
name = 'JS.$name'
}
f.write('fn ${receiver}${name}')
f.write('fn $receiver$name')
if node.is_generic {
f.write('<T>')
}
@ -70,8 +64,8 @@ pub fn (node &FnDecl) stringify(t &table.Table, cur_mod string) string {
continue
}
is_last_arg := i == node.args.len - 1
should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ || (node.is_variadic &&
i == node.args.len - 2)
should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ ||
(node.is_variadic && i == node.args.len - 2)
if arg.is_mut {
f.write(arg.typ.share().str() + ' ')
}
@ -105,7 +99,7 @@ pub fn (node &FnDecl) stringify(t &table.Table, cur_mod string) string {
}
pub fn (x &InfixExpr) str() string {
return '${x.left.str()} $x.op.str() ${x.right.str()}'
return '$x.left.str() $x.op.str() $x.right.str()'
}
// Expressions in string interpolations may have to be put in braces if they
@ -116,14 +110,14 @@ pub fn (x &InfixExpr) str() string {
// This method creates the format specifier (including the colon) or an empty
// string if none is needed and also returns (as bool) if the expression
// must be enclosed in braces.
pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) {
mut res := []string{}
needs_fspec := lit.need_fmts[i] || lit.pluss[i] || (lit.fills[i] && lit.fwidths[i] >= 0) || lit.fwidths[i] != 0 || lit.precisions[i] != 0
needs_fspec := lit.need_fmts[i] || lit.pluss[i] ||
(lit.fills[i] && lit.fwidths[i] >= 0) || lit.fwidths[i] != 0 || lit.precisions[i] != 0
mut needs_braces := needs_fspec
if !needs_braces {
if i+1 < lit.vals.len && lit.vals[i+1].len > 0 {
next_char := lit.vals[i+1][0]
if i + 1 < lit.vals.len && lit.vals[i + 1].len > 0 {
next_char := lit.vals[i + 1][0]
if util.is_func_char(next_char) || next_char == `.` || next_char == `(` {
needs_braces = true
}
@ -181,90 +175,94 @@ pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) {
pub fn (x Expr) str() string {
match x {
BoolLiteral {
return it.val.str()
return x.val.str()
}
CastExpr {
return '${it.typname}(${it.expr.str()})'
return '${x.typname}($x.expr.str())'
}
CallExpr {
sargs := args2str(it.args)
if it.is_method {
return '${it.left.str()}.${it.name}($sargs)'
sargs := args2str(x.args)
if x.is_method {
return '${x.left.str()}.${x.name}($sargs)'
}
return '${it.mod}.${it.name}($sargs)'
return '${x.mod}.${x.name}($sargs)'
}
CharLiteral {
return '`$it.val`'
return '`$x.val`'
}
EnumVal {
return '.${it.val}'
return '.$x.val'
}
FloatLiteral {
return it.val
return x.val
}
Ident {
return it.name
return x.name
}
IndexExpr {
return '${it.left.str()}[${it.index.str()}]'
return '$x.left.str()[$x.index.str()]'
}
IntegerLiteral {
return it.val
return x.val
}
InfixExpr {
return '${it.left.str()} $it.op.str() ${it.right.str()}'
return '$x.left.str() $x.op.str() $x.right.str()'
}
ParExpr {
return '($it.expr)'
return '($x.expr)'
}
PrefixExpr {
return it.op.str() + it.right.str()
return x.op.str() + x.right.str()
}
RangeExpr {
mut s := '..'
if it.has_low {s = '$it.low ' + s}
if it.has_high {s = s + ' $it.high'}
if x.has_low {
s = '$x.low ' + s
}
if x.has_high {
s = s + ' $x.high'
}
return s
}
SelectorExpr {
return '${it.expr.str()}.${it.field_name}'
return '${x.expr.str()}.$x.field_name'
}
SizeOf {
return 'sizeof($it.expr)'
return 'sizeof($x.expr)'
}
StringInterLiteral {
mut res := []string{}
res << "'"
for i, val in it.vals {
for i, val in x.vals {
res << val
if i >= it.exprs.len {
if i >= x.exprs.len {
break
}
res << '$'
fspec_str, needs_braces := it.get_fspec_braces(i)
fspec_str, needs_braces := x.get_fspec_braces(i)
if needs_braces {
res << '{'
res << it.exprs[i].str()
res << x.exprs[i].str()
res << fspec_str
res << '}'
} else {
res << it.exprs[i].str()
res << x.exprs[i].str()
}
}
res << "'"
return res.join('')
}
StringLiteral {
return '"$it.val"'
return '"$x.val"'
}
TypeOf {
return 'typeof(${it.expr.str()})'
return 'typeof($x.expr.str())'
}
Likely {
return '_likely_(${it.expr.str()})'
return '_likely_($x.expr.str())'
}
UnsafeExpr {
return 'unsafe { $it.expr }'
return 'unsafe { $x.expr }'
}
else {}
}
@ -273,9 +271,9 @@ pub fn (x Expr) str() string {
pub fn (a CallArg) str() string {
if a.is_mut {
return 'mut ${a.expr.str()}'
return 'mut $a.expr.str()'
}
return '${a.expr.str()}'
return '$a.expr.str()'
}
pub fn args2str(args []CallArg) string {
@ -290,7 +288,7 @@ pub fn (node Stmt) str() string {
match node {
AssignStmt {
mut out := ''
for i, left in it.left {
for i, left in node.left {
if left is Ident {
var_info := left.var_info()
if var_info.is_mut {
@ -302,20 +300,20 @@ pub fn (node Stmt) str() string {
out += ','
}
}
out += ' $it.op.str() '
for i, val in it.right {
out += ' $node.op.str() '
for i, val in node.right {
out += val.str()
if i < it.right.len - 1 {
if i < node.right.len - 1 {
out += ','
}
}
return out
}
ExprStmt {
return it.expr.str()
return node.expr.str()
}
FnDecl {
return 'fn ${it.name}() { $it.stmts.len stmts }'
return 'fn ${node.name}() { $node.stmts.len stmts }'
}
else {
return '[unhandled stmt str type: ${typeof(node)} ]'

View File

@ -96,10 +96,11 @@ pub fn (mut c Checker) check_scope_vars(sc &ast.Scope) {
}
}
}
// TODO: fix all of these warnings
// if obj.is_mut && !obj.is_changed {
// c.warn('`$obj.name` is declared as mutable, but it was never changed', obj.pos)
// }
if obj.is_mut && !obj.is_changed && !c.is_builtin_mod && obj.name != 'it' {
// if obj.is_mut && !obj.is_changed && !c.is_builtin { //TODO C error bad field not checked
// c.warn('`$obj.name` is declared as mutable, but it was never changed',
// obj.pos)
}
}
else {}
}
@ -555,7 +556,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
c.expected_type = former_expected_type
}
c.expected_type = table.void_type
mut left_type := c.expr(infix_expr.left)
left_type := c.expr(infix_expr.left)
// left_type = c.unwrap_genric(c.expr(infix_expr.left))
infix_expr.left_type = left_type
c.expected_type = left_type
@ -816,6 +817,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
}
// returns name and position of variable that needs write lock
// also sets `is_changed` to true (TODO update the name to reflect this?)
fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
mut to_lock := '' // name of variable that needs lock
mut pos := token.Position{} // and its position
@ -1518,7 +1520,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
return ret_type
}
pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) {
pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type) {
if or_expr.kind == .propagate {
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main' {
c.error('to propagate the optional call, `$c.cur_fn.name` must itself return an optional',
@ -1536,7 +1538,7 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type
// allow `f() or {}`
return
}
mut last_stmt := or_expr.stmts[stmts_len - 1]
last_stmt := or_expr.stmts[stmts_len - 1]
if ret_type != table.void_type {
match mut last_stmt {
ast.ExprStmt {
@ -2932,7 +2934,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
// since it is used in c.match_exprs() it saves checking twice
node.cond_type = cond_type
if cond_type == 0 {
c.error('match 0 cond type', node.pos)
c.error('compiler bug: match 0 cond type', node.pos)
}
cond_type_sym := c.table.get_type_symbol(cond_type)
if cond_type_sym.kind !in [.sum_type, .interface_] {
@ -2981,7 +2983,11 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
// node.expected_type = c.expected_type
// }
node.return_type = ret_type
// println('!m $expr_type')
if node.is_mut {
// Mark `x` in `match mut x {` as changed, and ensure it's mutable
// TODO2 enable when code is fixed
// c.fail_if_immutable(node.cond)
}
return ret_type
}

View File

@ -568,7 +568,7 @@ fn (p &Parser) fileis(s string) bool {
fn (mut p Parser) check_fn_mutable_arguments(typ table.Type, pos token.Position) {
sym := p.table.get_type_symbol(typ)
if sym.kind !in [.array, .struct_, .map, .placeholder] && !typ.is_ptr() {
if sym.kind !in [.array, .struct_, .map, .placeholder, .sum_type] && !typ.is_ptr() {
p.error_with_pos('mutable arguments are only allowed for arrays, maps, and structs\n' +
'return values instead: `fn foo(mut n $sym.name) {` => `fn foo(n $sym.name) $sym.name {`',
pos)

View File

@ -229,6 +229,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
typ: typ.to_ptr()
pos: cond_pos
is_used: true
is_changed: true // TODO mut unchanged warning hack, remove
is_mut: is_mut
})
}

View File

@ -44,7 +44,7 @@ pub mut:
is_fmt bool // Used only for skipping ${} in strings, since we need literal
// string values when generating formatted code.
comments_mode CommentsMode
is_inside_toplvl_statement bool // *only* used in comments_mode: .toplevel_comments, toggled by parser
is_inside_toplvl_statement bool // *only* used in comments_mode: .toplevel_comments, toggled by parser
all_tokens []token.Token // *only* used in comments_mode: .toplevel_comments, contains all tokens
tidx int
eofs int
@ -178,8 +178,8 @@ fn (mut s Scanner) ident_name() string {
return name
}
// ident_fn_name look ahead and return name of function if possible, otherwise empty string
fn (mut s Scanner) ident_fn_name() string {
// ident_fn_name looks ahead and returns name of the function if possible, otherwise an empty string
fn (s &Scanner) ident_fn_name() string {
start := s.pos
mut pos := s.pos
pos++
@ -221,9 +221,8 @@ fn (mut s Scanner) ident_fn_name() string {
if pos <= start || pos >= s.text.len {
return ''
}
if s.text[start_pos].is_digit() || end_pos > s.text.len ||
end_pos <= start_pos || end_pos <= start ||
start_pos < start {
if s.text[start_pos].is_digit() || end_pos > s.text.len || end_pos <= start_pos ||
end_pos <= start || start_pos < start {
return ''
}
fn_name := s.text[start_pos..end_pos]
@ -231,7 +230,7 @@ fn (mut s Scanner) ident_fn_name() string {
}
// ident_mod_name look ahead and return name of module this file belongs to if possible, otherwise empty string
fn (mut s Scanner) ident_mod_name() string {
fn (s &Scanner) ident_mod_name() string {
start := s.pos
mut pos := s.pos
pos++
@ -259,7 +258,7 @@ fn (mut s Scanner) ident_mod_name() string {
}
// ident_struct_name look ahead and return name of last encountered struct if possible, otherwise empty string
fn (mut s Scanner) ident_struct_name() string {
fn (s &Scanner) ident_struct_name() string {
start := s.pos
mut pos := s.pos
// Return last known stuct_name encountered to avoid using high order/anonymous function definitions
@ -303,9 +302,8 @@ fn (mut s Scanner) ident_struct_name() string {
return ''
}
start_pos := pos + 1
if s.text[start_pos].is_digit() || end_pos > s.text.len ||
end_pos <= start_pos || end_pos <= start ||
start_pos <= start {
if s.text[start_pos].is_digit() || end_pos > s.text.len || end_pos <= start_pos ||
end_pos <= start || start_pos <= start {
return ''
}
struct_name := s.text[start_pos..end_pos]
@ -354,8 +352,7 @@ fn (mut s Scanner) ident_bin_number() string {
}
if s.text[s.pos - 1] == num_sep {
s.error('cannot use `_` at the end of a numeric literal')
}
else if start_pos + 2 == s.pos {
} else if start_pos + 2 == s.pos {
s.pos-- // adjust error position
s.error('number part of this binary is not provided')
} else if has_wrong_digit {
@ -394,8 +391,7 @@ fn (mut s Scanner) ident_hex_number() string {
}
if s.text[s.pos - 1] == num_sep {
s.error('cannot use `_` at the end of a numeric literal')
}
else if start_pos + 2 == s.pos {
} else if start_pos + 2 == s.pos {
s.pos-- // adjust error position
s.error('number part of this hexadecimal is not provided')
} else if has_wrong_digit {
@ -434,8 +430,7 @@ fn (mut s Scanner) ident_oct_number() string {
}
if s.text[s.pos - 1] == num_sep {
s.error('cannot use `_` at the end of a numeric literal')
}
else if start_pos + 2 == s.pos {
} else if start_pos + 2 == s.pos {
s.pos-- // adjust error position
s.error('number part of this octal is not provided')
} else if has_wrong_digit {
@ -455,7 +450,7 @@ fn (mut s Scanner) ident_dec_number() string {
// scan integer part
for s.pos < s.text.len {
c := s.text[s.pos]
if c == num_sep && s.text[s.pos + 1] == num_sep {
if c == num_sep && s.text[s.pos + 1] == num_sep {
s.error('cannot use `_` consecutively')
}
if !c.is_digit() && c != num_sep {
@ -546,8 +541,7 @@ fn (mut s Scanner) ident_dec_number() string {
// error check: 5e
s.pos-- // adjust error position
s.error('exponent has no digits')
} else if s.pos < s.text.len &&
s.text[s.pos] == `.` && !is_range && !call_method {
} else if s.pos < s.text.len && s.text[s.pos] == `.` && !is_range && !call_method {
// error check: 1.23.4, 123.e+3.4
if has_exp {
s.error('exponential part should be integer')
@ -608,7 +602,7 @@ pub fn (mut s Scanner) scan_all_tokens_in_buffer() {
cmode := s.comments_mode
s.comments_mode = .parse_comments
for {
mut t := s.text_scan()
t := s.text_scan()
s.all_tokens << t
if t.kind == .eof {
break
@ -1093,7 +1087,7 @@ fn (mut s Scanner) text_scan() token.Token {
start := s.pos + 1
s.ignore_line()
mut comment_line_end := s.pos
if s.text[s.pos-1] == `\r` {
if s.text[s.pos - 1] == `\r` {
comment_line_end--
} else {
// fix line_nr, \n was read; the comment is marked on the next line
@ -1216,7 +1210,8 @@ fn (mut s Scanner) ident_string() string {
}
// Don't allow \0
if c == `0` && s.pos > 2 && s.text[s.pos - 1] == slash {
if (s.pos < s.text.len - 1 && s.text[s.pos + 1].is_digit()) || s.count_symbol_before(s.pos - 1, slash) % 2 == 0 {
if (s.pos < s.text.len - 1 && s.text[s.pos + 1].is_digit()) ||
s.count_symbol_before(s.pos - 1, slash) % 2 == 0 {
} else if !is_cstr && !is_raw {
s.error(r'cannot use `\0` (NULL character) in the string literal')
}
@ -1236,8 +1231,8 @@ fn (mut s Scanner) ident_string() string {
break
}
// $var
if prevc == `$` && util.is_name_char(c) && !is_raw &&
s.count_symbol_before(s.pos - 2, slash) % 2 == 0 {
if prevc == `$` && util.is_name_char(c) && !is_raw && s.count_symbol_before(s.pos - 2, slash) %
2 == 0 {
s.is_inside_string = true
s.is_inter_start = true
s.pos -= 2

View File

@ -13,7 +13,7 @@ const (
// compile_file compiles the content of a file by the given path as a template
pub fn compile_file(path, fn_name string) string {
mut html := os.read_file(path) or {
html := os.read_file(path) or {
panic('html failed')
}
return compile_template(html, fn_name)
@ -82,7 +82,7 @@ _ = footer
pos := line.index('@include ') or {
continue
}
mut file_name := line[pos + 9..]
file_name := line[pos + 9..]
file_path := os.join_path('templates', '${file_name}.html')
mut file_content := os.read_file(file_path) or {
panic('reading file $file_name failed')