Skip to content

Commit

Permalink
refactor(gen): handling of comptime pseudo vars (#156)
Browse files Browse the repository at this point in the history
- remove from Prefs and set them during codegen
- set only on usage
- properly print them in failed asserts
  • Loading branch information
serkonda7 authored Dec 21, 2023
1 parent 06e5c06 commit ab8671a
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 61 deletions.
1 change: 0 additions & 1 deletion cli/bait.bt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ fun main() {
args := os.user_args()
timers.start('PREFS')
mut prefs := preference.parse_args(args)
prefs.set_comptime_vars()
timers.set_show(prefs.show_timings)
timers.show('PREFS')

Expand Down
37 changes: 20 additions & 17 deletions docs/docs.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<!--
Copyright (c) 2023-present Lukas Neubert.
This Documentation is subject to the terms of the Mozilla Public License 2.0.
SPDX-FileCopyrightText: 2023-present Lukas Neubert <[email protected]>
SPDX-License-Identifier: MPL-2.0
-->

# Bait Documentation
> Documentation of the standard library is :construction:
> Documentation of the standard library is work in progress :construction:
## Entry Point
The entry point of any program is the `main` function. It is automatically called when the program starts.
Expand Down Expand Up @@ -424,28 +425,30 @@ struct FooBar {
| ----------- | ------------------------------------------- | ------ |
| `@required` | The field must be initialized with a value. | _none_ |


## Conditional Compilation
### Compile Time Pseudo Variables
Bait supports a few pseudo variables of `string` type.
They are replaced with the actual value during compilation.

| Variable | Description | Example |
| ------------ | ----------------------------------- | ----------------------- |
| `$PKG` | Name of the current package. | `main` |
| `$FILE` | Relative path of the source file. | `lib/builtin/file.bt` |
| `$ABS_FILE` | Absolute path of the source file. | `/path/to/file.bt` |
| `$LINE` | Line number of it's appearance. | `123` |
| `$FILE_LINE` | Relative path followed by the line. | `tests/my_test.bt:27` |
| `$FUN` | Name of the current function. | `test_read_line` |
| `$BAITEXE` | Absolut path to the Bait compiler. | `/path/to/bait/bait.js` |
| `$BAITDIR` | Directory where the compiler is in. | `/path/to/bait` |
| `$BAITHASH` | Short commit hash of the compiler. | `5e7fd6e` |
Bait supports a few pseudo variables, which are replaced by their actual values during compilation.
They are all of the type `string`.

| Variable | Description | Example |
| ------------ | --------------------------------- | ----------------------- |
| `$PKG` | Current package name | `main` |
| `$ABS_FILE` | Absolute source file path | `/path/to/file.bt` |
| `$FILE` | Relative source file path | `lib/builtin/file.bt` |
| `$LINE` | Line number where it is used | `123` |
| `$FILE_LINE` | Relative path and the line | `tests/my_test.bt:27` |
| `$FUN` | Current function name | `test_read_line` |
| `$BAITEXE` | Absolut path to the Bait compiler | `/path/to/bait/bait.js` |
| `$BAITDIR` | Directory of the compiler | `/path/to/bait` |
| `$BAITHASH` | The compiler's short commit hash | `5e7fd6e` |

They are useful for running external tools or debugging. For example:
```bait
eprintln('error in file ${$FILE}, line ${$LINE}, function ${$PKG}.${$FUN}')
```


## Global Variables
While the use of global variables is discouraged, they are important in some cases.

Expand Down
4 changes: 2 additions & 2 deletions lib/bait/ast/ast.bt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import bait.errors

type Stmt := AssertStmt | AssignStmt | ConstDecl | EnumDecl | ExprStmt | ForLoop | ForClassicLoop | ForInLoop | FunDecl | GlobalDecl | InterfaceDecl | ReturnStmt | StructDecl | TypeDecl | LoopControlStmt | EmptyStmt | MatchExpr | IfExpr

type Expr := AnonFun | ArrayInit | AsCast | BoolLiteral | CallExpr | CharLiteral | CompTimeVar | EnumVal | FloatLiteral | HashExpr | Ident | IfExpr | IndexExpr | InfixExpr | IntegerLiteral | MatchExpr | MapInit | ParExpr | PrefixExpr | SelectorExpr | StringLiteral | StringInterLiteral | StructInit | TypeOf | EmptyExpr
type Expr := AnonFun | ArrayInit | AsCast | BoolLiteral | CallExpr | CharLiteral | ComptimeVar | EnumVal | FloatLiteral | HashExpr | Ident | IfExpr | IndexExpr | InfixExpr | IntegerLiteral | MatchExpr | MapInit | ParExpr | PrefixExpr | SelectorExpr | StringLiteral | StringInterLiteral | StructInit | TypeOf | EmptyExpr

pub struct AssertStmt {
pub:
Expand Down Expand Up @@ -237,7 +237,7 @@ pub:
pos token.Pos
}

pub struct CompTimeVar{
pub struct ComptimeVar{
pub:
name string
pos token.Pos
Expand Down
6 changes: 3 additions & 3 deletions lib/bait/checker/expr.bt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ fun (mut c Checker) expr(expr ast.Expr) ast.Type {
return c.call_expr(expr)
} else if expr is ast.CharLiteral {
return ast.U8_TYPE
} else if expr is ast.CompTimeVar {
return c.comp_time_var(expr)
} else if expr is ast.ComptimeVar {
return c.comptime_var(expr)
} else if expr is ast.EnumVal {
return c.enum_val(expr)
} else if expr is ast.FloatLiteral {
Expand Down Expand Up @@ -155,7 +155,7 @@ const SUPPORTED_COMPTIME_VARS := [
'BAITHASH',
]

fun (mut c Checker) comp_time_var(node ast.CompTimeVar) ast.Type {
fun (mut c Checker) comptime_var(node ast.ComptimeVar) ast.Type {
if not SUPPORTED_COMPTIME_VARS.contains(node.name) {
c.error('unsupported comptime var "${node.name}"', node.pos)
}
Expand Down
55 changes: 55 additions & 0 deletions lib/bait/gen/js/comptime.bt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2023-present Lukas Neubert <[email protected]>
// SPDX-License-Identifier: MPL-2.0
package js

import os
import bait.ast
import bait.token

fun (mut g Gen) comptime_var(node ast.ComptimeVar){
g.write('from_js_string("')
g.write(g.get_comptime_val(node.name, node.pos))
g.write('")')
}

fun (mut g Gen) get_comptime_val(name string, pos token.Pos) string {
return match name {
// Dynamic
'PKG' { g.pkg }
'ABS_FILE' { os.abs_path(g.path).replace('\\', '\\\\') }
'FILE' { g.path.replace('\\', '\\\\') }
'LINE' { pos.line.str() }
'FILE_LINE' {
file := g.get_comptime_val('FILE', pos)
line := g.get_comptime_val('LINE', pos)
'${file}:${line}'
}
'FUN' { g.cur_fun.name }
// Cached
'BAITEXE' { g.comptime_baitexe() }
'BAITDIR' { g.comptime_baitdir() }
'BAITHASH' { g.comptime_baithash() }
}
}

fun (mut g Gen) comptime_baitexe() string {
if g.baitexe.length == 0 {
g.baitexe = os.executable().replace('\\', '\\\\')
}
return g.baitexe
}

fun (mut g Gen) comptime_baitdir() string {
if g.baitdir.length == 0 {
g.baitdir = os.dir(g.comptime_baitexe()).trim_right('\\')
}
return g.baitdir
}

fun (mut g Gen) comptime_baithash() string {
if g.baithash.length == 0 {
bd := g.comptime_baitdir()
g.baithash = os.exec('git -C ${bd} rev-parse --short HEAD').stdout.trim_space()
}
return g.baithash
}
20 changes: 2 additions & 18 deletions lib/bait/gen/js/expr.bt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ fun (mut g Gen) expr(expr ast.Expr) {
g.call_expr(expr)
} else if expr is ast.CharLiteral {
g.char_literal(expr)
} else if expr is ast.CompTimeVar {
g.comp_time_var(expr)
} else if expr is ast.ComptimeVar {
g.comptime_var(expr)
} else if expr is ast.EnumVal {
g.enum_val(expr)
} else if expr is ast.FloatLiteral {
Expand Down Expand Up @@ -131,22 +131,6 @@ fun (mut g Gen) char_literal(node ast.CharLiteral) {
g.write('")')
}

fun (mut g Gen) comp_time_var(node ast.CompTimeVar){
g.write('from_js_string("')
match node.name{
'PKG' {g.write(g.pkg)}
'FILE' {g.write(g.path.replace('\\', '\\\\'))}
'ABS_FILE' {g.write(os.abs_path(g.path).replace('\\', '\\\\'))}
'LINE' {g.write('${node.pos.line}')}
'FILE_LINE' {g.write('${g.path.replace('\\', '\\\\')}:${node.pos.line}')}
'FUN' {g.write(g.cur_fun.name)}
'BAITEXE' {g.write(g.pref.baitexe)}
'BAITDIR' {g.write(g.pref.baitdir)}
'BAITHASH' {g.write(g.pref.baithash)}
}
g.write('")')
}

fun (mut g Gen) enum_val(node ast.EnumVal) {
g.write(js_name(node.name) + '.' + node.val)
}
Expand Down
4 changes: 4 additions & 0 deletions lib/bait/gen/js/jsgen.bt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ mut:
is_for_loop_head bool
is_lhs_assign bool
is_array_map_set bool
// Cached comptime variables
baitexe string
baitdir string
baithash string
}

pub fun gen(files []ast.File, table ast.Table, pref preference.Prefs) string {
Expand Down
3 changes: 3 additions & 0 deletions lib/bait/gen/js/stmt.bt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ fun (mut g Gen) assert_side_expr(node ast.Expr) {
} else if node is ast.SelectorExpr {
g.assert_side_expr(node.expr)
g.write('.${node.field_name}')
} else if node is ast.ComptimeVar {
g.write('$')
g.write(node.name)
} else {
g.write('UNHANDLED EXPR')
}
Expand Down
6 changes: 3 additions & 3 deletions lib/bait/parser/expr.bt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fun (mut p Parser) single_expr() ast.Expr {
return p.char_literal()
}
.dollar {
return p.comp_time_var()
return p.comptime_var()
}
.dot {
return p.enum_val(false)
Expand Down Expand Up @@ -191,11 +191,11 @@ fun (mut p Parser) char_literal()ast.CharLiteral{
}
}

fun (mut p Parser) comp_time_var() ast.CompTimeVar{
fun (mut p Parser) comptime_var() ast.ComptimeVar{
pos := p.pos()
p.next()
name := p.check_name()
return ast.CompTimeVar{
return ast.ComptimeVar{
name = name
pos = pos
}
Expand Down
11 changes: 0 additions & 11 deletions lib/bait/preference/preference.bt
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ pub mut:
// Error related
hide_warnings bool
warn_is_error bool

// Values for compile time pseudo variables
baitexe string
baitdir string
baithash string
}

pub fun parse_args(args []string) Prefs {
Expand Down Expand Up @@ -152,12 +147,6 @@ pub fun parse_args(args []string) Prefs {
return p
}

pub fun (mut p Prefs) set_comptime_vars() {
p.baitexe = os.executable().replace('\\', '\\\\')
p.baitdir = os.dir(p.baitexe).trim_right('\\')
p.baithash = os.exec('git -C ${p.baitdir} rev-parse --short HEAD').stdout.trim_space()
}

fun backend_from_string(s string) Backend {
return match s {
'js' { Backend.js }
Expand Down
22 changes: 22 additions & 0 deletions tests/other/comptime_vars_test.bt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2023-present Lukas Neubert <[email protected]>
// SPDX-License-Identifier: MPL-2.0

import os

fun test_comptime_vars() {
assert $PKG == 'main'
assert $FILE == 'tests/other/comptime_vars_test.bt'.replace('/', os.PATH_SEP)
assert $LINE == '9'
assert $FILE_LINE == 'tests/other/comptime_vars_test.bt:10'.replace('/', os.PATH_SEP)
assert $FUN == 'test_comptime_vars'

// The following vars are hard to test

assert $ABS_FILE.length > $FILE.length

assert $BAITEXE.length > 0

assert $BAITDIR.length < $BAITEXE.length

assert $BAITHASH.length == 7
}
4 changes: 2 additions & 2 deletions tests/other/number_test.bt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2023-present Lukas Neubert.
// This Source Codeubject to the terms of the Mozilla Public License 2.0.
// SPDX-FileCopyrightText: 2023-present Lukas Neubert <[email protected]>
// SPDX-License-Identifier: MPL-2.0

fun test_floats() {
f := 1.23
Expand Down
4 changes: 2 additions & 2 deletions tests/other/ptr_deref_test.bt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2023-present Lukas Neubert.
// This Source Codeubject to the terms of the Mozilla Public License 2.0.
// SPDX-FileCopyrightText: 2023-present Lukas Neubert <[email protected]>
// SPDX-License-Identifier: MPL-2.0

fun test_pointer_deref() {
n := 42
Expand Down
4 changes: 2 additions & 2 deletions tests/other/u8_test.bt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2023-present Lukas Neubert.
// This Source Codeubject to the terms of the Mozilla Public License 2.0.
// SPDX-FileCopyrightText: 2023-present Lukas Neubert <[email protected]>
// SPDX-License-Identifier: MPL-2.0

fun test_u8_operations() {
a := `a`
Expand Down

0 comments on commit ab8671a

Please sign in to comment.