cgen/ast/checker: string interpolation
parent
c21e976cad
commit
5072320803
|
@ -55,6 +55,26 @@ pub fn (b mut Builder) writeln(s string) {
|
|||
b.len += s.len + 1
|
||||
}
|
||||
|
||||
// buf == 'hello world'
|
||||
// last_n(5) returns 'world'
|
||||
pub fn (b mut Builder) last_n(n int) string {
|
||||
if n > b.len {
|
||||
return ''
|
||||
}
|
||||
buf := b.buf[b.len-n..]
|
||||
return string(buf.clone())
|
||||
}
|
||||
|
||||
// buf == 'hello world'
|
||||
// after(6) returns 'world'
|
||||
pub fn (b mut Builder) after(n int) string {
|
||||
if n >= b.len {
|
||||
return ''
|
||||
}
|
||||
buf := b.buf[n..]
|
||||
return string(buf.clone())
|
||||
}
|
||||
|
||||
pub fn (b mut Builder) str() string {
|
||||
b.buf << `\0`
|
||||
return string(b.buf,b.len)
|
||||
|
|
|
@ -14,7 +14,7 @@ pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLitera
|
|||
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
|
||||
AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr | MatchExpr |
|
||||
CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr |
|
||||
ConcatExpr | Type | AsCast | TypeOf
|
||||
ConcatExpr | Type | AsCast | TypeOf | StringInterLiteral
|
||||
|
||||
pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
|
||||
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
|
||||
|
@ -54,6 +54,15 @@ pub:
|
|||
val string
|
||||
}
|
||||
|
||||
// 'name: $name'
|
||||
pub struct StringInterLiteral {
|
||||
pub:
|
||||
vals []string
|
||||
exprs []Expr
|
||||
mut:
|
||||
expr_types []table.Type
|
||||
}
|
||||
|
||||
pub struct CharLiteral {
|
||||
pub:
|
||||
val string
|
||||
|
|
|
@ -393,7 +393,8 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
|
|||
return
|
||||
}
|
||||
if expected_types.len > 0 && expected_types.len != got_types.len {
|
||||
c.error('wrong number of return arguments:\n\texpected: $expected_types.str()\n\tgot: $got_types.str()', return_stmt.pos)
|
||||
// c.error('wrong number of return arguments:\n\texpected: $expected_types.str()\n\tgot: $got_types.str()', return_stmt.pos)
|
||||
c.error('wrong number of return arguments', return_stmt.pos)
|
||||
}
|
||||
for i, exp_typ in expected_types {
|
||||
got_typ := got_types[i]
|
||||
|
@ -737,6 +738,12 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
|||
ast.StringLiteral {
|
||||
return table.string_type
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
for expr in it.exprs {
|
||||
it.expr_types << c.expr(expr)
|
||||
}
|
||||
return table.string_type
|
||||
}
|
||||
ast.StructInit {
|
||||
return c.struct_init(mut it)
|
||||
}
|
||||
|
|
|
@ -868,6 +868,9 @@ fn (g mut Gen) expr(node ast.Expr) {
|
|||
g.write('tos3("$escaped_val")')
|
||||
}
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
g.string_inter_literal(it)
|
||||
}
|
||||
// `user := User{name: 'Bob'}`
|
||||
ast.StructInit {
|
||||
styp := g.typ(it.typ)
|
||||
|
@ -1652,6 +1655,46 @@ fn (g &Gen) sort_structs(types []table.TypeSymbol) []table.TypeSymbol {
|
|||
return types_sorted
|
||||
}
|
||||
|
||||
fn (g mut Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||
g.write('_STR("')
|
||||
// Build the string with %
|
||||
for i, val in node.vals {
|
||||
g.write(val)
|
||||
if i >= node.exprs.len {
|
||||
continue
|
||||
}
|
||||
pos := g.out.len
|
||||
match node.expr_types[i] {
|
||||
table.string_type {
|
||||
g.write('%.*s')
|
||||
}
|
||||
table.int_type {
|
||||
g.write('%d')
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
g.write('", ')
|
||||
// Build args
|
||||
for i, expr in node.exprs {
|
||||
if node.expr_types[i] == table.string_type {
|
||||
// `name.str, name.len,`
|
||||
g.expr(node.exprs[i])
|
||||
g.write('.len, ')
|
||||
g.expr(node.exprs[i])
|
||||
g.write('.str')
|
||||
}
|
||||
else {
|
||||
g.expr(node.exprs[i])
|
||||
}
|
||||
if i < node.exprs.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
// `nums.filter(it % 2 == 0)`
|
||||
fn (g mut Gen) gen_filter(node ast.MethodCallExpr) {
|
||||
tmp := g.new_tmp_var()
|
||||
buf := g.out.buf[g.stmt_start_pos..]
|
||||
|
|
|
@ -37,6 +37,11 @@ tos3(""),
|
|||
if (a == 10 || a == 20 || a == 30) {
|
||||
int b = 10;
|
||||
}
|
||||
string name = tos3("Bob");
|
||||
println(tos3("hello"));
|
||||
println(_STR("Hello, %.*s", name.len, name.str));
|
||||
println(_STR("age = %d", age));
|
||||
println(_STR("name=%.*s age=%d", name.len, name.str, age));
|
||||
}
|
||||
|
||||
void println(string s) {
|
||||
|
|
|
@ -30,6 +30,11 @@ fn (u &User) foo() {
|
|||
if a in [10, 20, 30] {
|
||||
b := 10
|
||||
}
|
||||
name := 'Bob'
|
||||
println('hello')
|
||||
println('Hello, $name')
|
||||
println('age = $age')
|
||||
println('name=$name age=$age')
|
||||
}
|
||||
|
||||
fn println(s string) {}
|
||||
|
|
|
@ -1243,21 +1243,25 @@ fn (p mut Parser) if_expr() ast.IfExpr {
|
|||
|
||||
fn (p mut Parser) string_expr() ast.Expr {
|
||||
mut node := ast.Expr{}
|
||||
val := p.tok.lit
|
||||
node = ast.StringLiteral{
|
||||
val: p.tok.lit
|
||||
val: val
|
||||
}
|
||||
if p.peek_tok.kind != .str_dollar {
|
||||
p.next()
|
||||
return node
|
||||
}
|
||||
mut exprs := []ast.Expr
|
||||
mut vals := []string
|
||||
// Handle $ interpolation
|
||||
for p.tok.kind == .string {
|
||||
vals << p.tok.lit
|
||||
p.next()
|
||||
if p.tok.kind != .str_dollar {
|
||||
continue
|
||||
}
|
||||
p.check(.str_dollar)
|
||||
p.expr(0)
|
||||
exprs << p.expr(0)
|
||||
if p.tok.kind == .colon {
|
||||
p.next()
|
||||
}
|
||||
|
@ -1273,6 +1277,10 @@ fn (p mut Parser) string_expr() ast.Expr {
|
|||
}
|
||||
}
|
||||
}
|
||||
node = ast.StringInterLiteral{
|
||||
vals: vals
|
||||
exprs: exprs
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue