Skip to content

Commit

Permalink
beat saber
Browse files Browse the repository at this point in the history
  • Loading branch information
StackDoubleFlow committed Aug 22, 2021
1 parent 360dea3 commit 4eaf188
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 36 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ anyhow = "1.0"
clap = "3.0.0-beta.4"
codespan-reporting = "0.11"
unescape = "0.1"
cc = "1"
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,32 @@ For langjam

## Documentation

See [docs]("docs") for more info.
See [docs](docs) for more info.

### Prerequisites

* GCC
* A compatible C compiler
* LLVM 12
* Rust

### Getting Started

See [getting-started]("docs/getting_started.md")
See [getting-started](docs/getting_started.md)

### Building the compiler

```bash
./build_example.sh
./beatsaber
# Compile to ./target/release/bsc
cargo build --release
# Or alternatively install to ~/.cargo/bin
cargo install --path .
```

TODO:
### Compiling the example

- Error reporting done
- String literals done
- Extern "C" blocks no
- Dynamic dlopens (grammar supported, still needs emitted asm for dlopen)
- Docs/more examples more examples yes, docs no
- Gotos done
```bash
# Compile the beatsaber program
bsc examples/beatsaber.beatsaber -o beatsaber
# Run the result
./beatsaber
```
9 changes: 9 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
macro_rules! reexport_env {
($var:literal) => {
println!(concat!("cargo:rustc-env=", $var, "={}"), ::std::env::var($var).unwrap())
};
}

fn main() {
reexport_env!("HOST");
}
3 changes: 0 additions & 3 deletions build_example.sh

This file was deleted.

10 changes: 3 additions & 7 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Welcome to beat saber
## Building

```bash
bsc your_cool_program.beatsaber
bsc your_cool_program.beatsaber -I stdlib.c -o output_executable
./output_executable
```

## Development
Expand All @@ -16,9 +17,4 @@ bsc your_cool_program.beatsaber
res. // yeet is puts
```

## Execution

```bash
gcc your_cool_program.o stdlib.o -o output_executable
./output_executable
```
See [grammar](grammar.md) and [syntax](syntax.md) for more info.
10 changes: 7 additions & 3 deletions docs/grammar.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The following is a non-exhaustive list of all currently supported keywords in be
- Used to chain multiple operators together in expressions.
- `a.. // yeet is inc then inc`
- `with`
- Used to declare a function with one or two parameters
- Used to declare a function with one or two parameters. Functions can shadow values outside of functions, and can also use identifiers defined before. Identifiers are captured by value.
- `// my_func is with a`
- `if`
- Used to evaluate conditionally based off of an evaluated identifier.
Expand All @@ -32,7 +32,7 @@ The following is a non-exhaustive list of all currently supported keywords in be
- `but is in`
- Specifies a module name that an external function can be found in.
- `// malloc_special is not here but is in libthing.so`
- `and is big`
- `this is big`
- Specifies an external function requires two parameters instead of one.
- `// calloc is not here this is big`
- `return`
Expand All @@ -54,8 +54,12 @@ Identifiers can be shadowed, except for functions, which must not be shadowed, i

Identifiers are typically used with operators, but are also used in behaviours. For example, `if`, `with`, `and`, and actual operations must be used with identifiers.

There are two special identifiers that exist implicitly: `argc` and `argv`.

## Operations

The only operator in beat saber is `.`. This is used for unary operations (`a.`) and binary operations (`a.b`).
The only operator in beat saber is `.`

This is used for unary operations (`a.`) and binary operations (`a.b`).

In order to specify the operation, you must provide an operation for each `.` you provide in your statement. These will be bound to the operations in tree-parse order (first evaluated first).
14 changes: 14 additions & 0 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ As an example, each of these lines is a statement.
res. // yeet is puts
```

All values in beat saber are 64bit unsigned integers. Pointers are expressed no differently than other numbers, as is the case for string literals.

## Statements

Each line (that is not a comment) is perceived as a statement.
Expand Down Expand Up @@ -43,7 +45,19 @@ puts(res);
## Expressions
Identifiers, optionally paired with operators, are expressions.
They are evaluated at the point of execution with when they fire, in tree parsing order.
The following are some examples of expressions:
`a`, `a.`, `a.b`
The first is simply the "value of" identifier `a`, while the second and third are call expressions. That is, they perform a unary (`a.`) and binary operation (`a.b`) as determined in the behaviour.
## Behaviours
Behaviours are what make up the latter half of a statement. They must always be after the "keyword" `//`.
Behaviours include assignment, function declarations/definitions, among many other types of behaviour. Ultimately, they are what control the flow of a beat saber program and also determine the operations to perform on expressions.
See [grammar](grammar.md) for more details on behaviours and how they can be constructed from keywords.
2 changes: 1 addition & 1 deletion examples/bf.beatsaber
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ new_ip // still in parse_lend if eq return is
loop_start2 // still in parse_lend goto is

// loop is 88
ip..zero // cond is deref then not
ip.. // cond is deref then not
zero // if cond return is
ip. // inst is deref

Expand Down
1 change: 0 additions & 1 deletion examples/test.bf

This file was deleted.

1 change: 1 addition & 0 deletions src/ast2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::collections::HashMap;
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct Identifier {
pub id: usize,
//pub name: Span,
}

#[derive(Clone, Debug)]
Expand Down
15 changes: 8 additions & 7 deletions src/bsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ struct Args {
/// Input source file path.
input: String,
/// Output object file path.
#[clap(short)]
output: Option<String>,
#[clap(short, default_value = "a.out")]
output: PathBuf,
/// Target triple
#[clap(long)]
target: Option<String>,
Expand All @@ -24,20 +24,20 @@ struct Args {
/// Generate position independent code
#[clap(long)]
pic: bool,
/// C source files to compile and link
#[clap(short = 'I')]
include_c: Vec<String>,
}

fn main() -> Result<()> {
let args = Args::parse();

let output_path = PathBuf::from(args.output.as_ref().unwrap_or(&args.input));
let object_path = output_path.with_extension("o");

let src = fs::read_to_string(&args.input).unwrap();
let lexer = lexer::lexer(&src, &args.input);
let parser = ast1::parser(lexer);
let ast2 = ast2::parse(parser);
let options = CodegenOptions {
output: object_path.as_path(),
output: args.output.as_path(),
optimization: match args.optimization {
0 => codegen::OptLevel::None,
1 => codegen::OptLevel::Less,
Expand All @@ -47,8 +47,9 @@ fn main() -> Result<()> {
},
pic: args.pic,
target: args.target,
include_c: args.include_c
};
dbg!(&ast2);
// dbg!(&ast2);
codegen::Codegen::compile(ast2, options)?;

Ok(())
Expand Down
48 changes: 46 additions & 2 deletions src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use inkwell::{AddressSpace, OptimizationLevel};
use std::collections::{BTreeMap, HashMap};
use std::mem;
use std::path::Path;
use std::io::Write;

/// Look for any identifier that is not declared in this function and assume they are captures.
fn find_captures(stmts: &[ast2::DecoratedStmt], params: &[usize]) -> Vec<usize> {
Expand Down Expand Up @@ -97,6 +98,7 @@ pub struct CodegenOptions<'a> {
pub pic: bool,
/// Target triple, None for host
pub target: Option<String>,
pub include_c: Vec<String>,
}

pub struct Codegen<'ctx> {
Expand Down Expand Up @@ -515,11 +517,53 @@ impl<'ctx> Codegen<'ctx> {
.create_target_machine(&triple, &cpu, &features, opt, reloc, model)
.unwrap();

self.module.print_to_stderr();
// self.module.print_to_stderr();
let tmp_out = format!("{}.tmp", options.output.display());
target_machine
.write_to_file(&self.module, FileType::Object, options.output)
.write_to_file(&self.module, FileType::Object, Path::new(&tmp_out))
.unwrap();

let includes = options.include_c.iter().map(|c| self.compile_c(c, &triple, opt as u32)).collect::<Result<Vec<_>, _>>()?;

let cc = cc::Build::new().target(triple.as_str().to_str().unwrap()).host(env!("HOST")).opt_level(opt as u32).cargo_metadata(false).try_get_compiler()?;
let out_path_flag = if cc.is_like_msvc() {
format!("/Fo\"{}\"", options.output.display())
} else {
format!("-o{}", options.output.display())
};
let output = cc.to_command().arg(&tmp_out).args(includes.iter()).arg(out_path_flag).output()?;
if !output.status.success() {
std::io::stderr().lock().write_all(&output.stderr)?;
std::io::stderr().lock().write_all(&output.stderr)?;
}

std::fs::remove_file(tmp_out)?;
for include in includes {
std::fs::remove_file(include)?;
}

Ok(())
}

fn compile_c(&self, file: impl AsRef<Path>, target: &TargetTriple, opt: u32) -> Result<String> {
let file = file.as_ref();
let out_file = format!("{}.tmp", file.display());
let cc = cc::Build::new().target(target.as_str().to_str().unwrap()).host(env!("HOST")).opt_level(opt).cargo_metadata(false).try_get_compiler()?;
let no_link_flag = if cc.is_like_msvc() {
"/c"
} else {
"-c"
};
let out_path_flag = if cc.is_like_msvc() {
format!("/Fo\"{}\"", out_file)
} else {
format!("-o{}", out_file)
};
let output = cc.to_command().arg(file).arg(no_link_flag).arg(out_path_flag).output()?;
if !output.status.success() {
std::io::stderr().lock().write_all(&output.stderr)?;
std::io::stderr().lock().write_all(&output.stderr)?;
}
Ok(out_file)
}
}

0 comments on commit 4eaf188

Please sign in to comment.