cgen/ast/checker: string interpolation

pull/4088/head
Alexander Medvednikov 2020-03-21 07:01:06 +01:00
parent c21e976cad
commit 5072320803
7 changed files with 101 additions and 4 deletions

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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..]

View File

@ -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) {

View File

@ -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) {}

View File

@ -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
}