cgen: optionals

pull/4007/head^2
Alexander Medvednikov 2020-03-13 05:57:51 +01:00
parent 9bcb7d115f
commit b173cea177
6 changed files with 96 additions and 56 deletions

View File

@ -247,6 +247,7 @@ pub mut:
typ table.Type typ table.Type
is_mut bool is_mut bool
is_static bool is_static bool
is_optional bool
} }
pub type IdentInfo = IdentFn | IdentVar pub type IdentInfo = IdentFn | IdentVar

View File

@ -733,6 +733,7 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
ident.kind = .variable ident.kind = .variable
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ typ: typ
is_optional: table.type_is_optional(typ)
} }
return typ return typ
} }

View File

@ -51,7 +51,7 @@ pub fn (g mut Gen) init() {
} }
// V type to C type // V type to C type
pub fn (g &Gen) typ(t table.Type) string { pub fn (g mut Gen) typ(t table.Type) string {
nr_muls := table.type_nr_muls(t) nr_muls := table.type_nr_muls(t)
sym := g.table.get_type_symbol(t) sym := g.table.get_type_symbol(t)
mut styp := sym.name.replace_each(['.', '__']) mut styp := sym.name.replace_each(['.', '__'])
@ -65,6 +65,10 @@ pub fn (g &Gen) typ(t table.Type) string {
// TODO perf and other C structs // TODO perf and other C structs
styp = 'struct stat' styp = 'struct stat'
} }
if table.type_is_optional(t) {
styp = 'Option_' + styp
g.definitions.writeln('typedef Option $styp;')
}
return styp return styp
} }
@ -264,26 +268,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
} }
ast.Import {} ast.Import {}
ast.Return { ast.Return {
g.write('return') g.return_statement(it)
// multiple returns
if it.exprs.len > 1 {
styp := g.typ(g.fn_decl.return_type)
g.write(' ($styp){')
for i, expr in it.exprs {
g.write('.arg$i=')
g.expr(expr)
if i < it.exprs.len - 1 {
g.write(',')
}
}
g.write('}')
}
// normal return
else if it.exprs.len == 1 {
g.write(' ')
g.expr(it.exprs[0])
}
g.writeln(';')
} }
ast.StructDecl { ast.StructDecl {
name := it.name.replace('.', '__') name := it.name.replace('.', '__')
@ -621,13 +606,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(it.val) g.write(it.val)
} }
ast.Ident { ast.Ident {
name := it.name.replace('.', '__') g.ident(it)
if name.starts_with('C__') {
g.write(name[3..])
}
else {
g.write(name)
}
} }
ast.IfExpr { ast.IfExpr {
// If expression? Assign the value to a temp var. // If expression? Assign the value to a temp var.
@ -798,7 +777,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(')') g.write(')')
} }
ast.None { ast.None {
g.write('0') g.write('opt_none()')
} }
ast.ParExpr { ast.ParExpr {
g.write('(') g.write('(')
@ -965,6 +944,27 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) {
} }
} }
fn (g mut Gen) ident(node ast.Ident) {
name := node.name.replace('.', '__')
if name.starts_with('C__') {
g.write(name[3..])
}
else {
// TODO `is`
match node.info {
ast.IdentVar {
if it.is_optional {
styp := g.typ(it.typ)[7..] // Option_int => int TODO perf?
g.write('(*($styp*)${name}.data)')
return
}
}
else {}
}
g.write(name)
}
}
fn (g mut Gen) index_expr(node ast.IndexExpr) { fn (g mut Gen) index_expr(node ast.IndexExpr) {
// TODO else doesn't work with sum types // TODO else doesn't work with sum types
mut is_range := false mut is_range := false
@ -1041,6 +1041,51 @@ fn (g mut Gen) index_expr(node ast.IndexExpr) {
} }
} }
fn (g mut Gen) return_statement(it ast.Return) {
g.write('return')
// multiple returns
if it.exprs.len > 1 {
styp := g.typ(g.fn_decl.return_type)
g.write(' ($styp){')
for i, expr in it.exprs {
g.write('.arg$i=')
g.expr(expr)
if i < it.exprs.len - 1 {
g.write(',')
}
}
g.write('}')
}
// normal return
else if it.exprs.len == 1 {
g.write(' ')
// `return opt_ok(expr)` for functions that expect an optional
if table.type_is_optional(g.fn_decl.return_type) {
mut is_none := false
mut is_error := false
match it.exprs[0] {
ast.None {
is_none = true
}
ast.CallExpr {
is_error = true // TODO check name 'error'
}
else {}
}
if !is_none && !is_error {
g.write('opt_ok(')
g.expr(it.exprs[0])
styp := g.typ(g.fn_decl.return_type)[7..] // remove 'Option_'
g.writeln(', sizeof($styp));')
return
}
// g.write('/*OPTIONAL*/')
}
g.expr(it.exprs[0])
}
g.writeln(';')
}
fn (g mut Gen) const_decl(node ast.ConstDecl) { fn (g mut Gen) const_decl(node ast.ConstDecl) {
for i, field in node.fields { for i, field in node.fields {
name := field.name.replace('.', '__') name := field.name.replace('.', '__')

View File

@ -1,5 +0,0 @@
// 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 table

View File

@ -1,18 +0,0 @@
module table
import os
// Once we have a module format we can read from module file instead
// this is not optimal
pub fn (table &Table) qualify_module(mod string, file_path string) string {
for m in table.imports {
if m.contains('.') && m.contains(mod) {
m_parts := m.split('.')
m_path := m_parts.join(os.path_separator)
if mod == m_parts[m_parts.len - 1] && file_path.contains(m_path) {
return m
}
}
}
return mod
}

View File

@ -5,6 +5,7 @@ module table
import ( import (
strings strings
os
) )
pub struct Table { pub struct Table {
@ -494,3 +495,18 @@ pub fn (t &Table) check(got, expected Type) bool {
} }
return true return true
} }
// Once we have a module format we can read from module file instead
// this is not optimal
pub fn (table &Table) qualify_module(mod string, file_path string) string {
for m in table.imports {
if m.contains('.') && m.contains(mod) {
m_parts := m.split('.')
m_path := m_parts.join(os.path_separator)
if mod == m_parts[m_parts.len - 1] && file_path.contains(m_path) {
return m
}
}
}
return mod
}