Compare commits
No commits in common. "old-master" and "master" have entirely different histories.
old-master
...
master
22 changed files with 957 additions and 846 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,2 @@
|
||||||
/target
|
/target
|
||||||
/a.out
|
.direnv
|
||||||
/*.o
|
|
||||||
|
|
994
Cargo.lock
generated
994
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
25
Cargo.toml
25
Cargo.toml
|
@ -1,21 +1,18 @@
|
||||||
[package]
|
[package]
|
||||||
name = "gust"
|
name = "gust"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Michael Zhang <mail@mzhang.io>"]
|
edition = "2021"
|
||||||
edition = "2018"
|
|
||||||
|
[[bin]]
|
||||||
|
name = "gustc"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.71"
|
||||||
cranelift = "0.69.0"
|
chalk-engine = "0.91.0"
|
||||||
cranelift-module = "0.69.0"
|
clap = { version = "4.3.9", features = ["derive"] }
|
||||||
cranelift-object = "0.69.0"
|
lalrpop-util = { version = "0.20.0", features = ["lexer", "regex", "unicode"] }
|
||||||
lalrpop-util = "0.19.4"
|
redb = "1.0.1"
|
||||||
lazy_static = "1.4.0"
|
|
||||||
parking_lot = "0.11.1"
|
|
||||||
petgraph = "0.5.1"
|
|
||||||
regex = "1.4.3"
|
|
||||||
structopt = "0.3.21"
|
|
||||||
target-lexicon = "0.11.1"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
lalrpop = "0.19.4"
|
lalrpop = "0.20.0"
|
||||||
|
|
2
build.rs
2
build.rs
|
@ -1,3 +1,3 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
lalrpop::process_root().unwrap();
|
lalrpop::process_root().unwrap();
|
||||||
}
|
}
|
||||||
|
|
12
default.nix
Normal file
12
default.nix
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{ toolchain, makeRustPlatform, pkg-config }:
|
||||||
|
|
||||||
|
let rustPlatform = makeRustPlatform { inherit (toolchain) cargo rustc; };
|
||||||
|
|
||||||
|
in rustPlatform.buildRustPackage {
|
||||||
|
name = "liveterm";
|
||||||
|
src = ./.;
|
||||||
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ pkg-config ];
|
||||||
|
buildInputs = [ ];
|
||||||
|
}
|
10
example
10
example
|
@ -1,10 +0,0 @@
|
||||||
fn main() {
|
|
||||||
let x = ();
|
|
||||||
urmom();
|
|
||||||
isEven();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn urmom(x: ()) { return (); }
|
|
||||||
|
|
||||||
fn isEven() { return isOdd(); }
|
|
||||||
fn isOdd() { return isEven(); }
|
|
5
examples/main.gs
Normal file
5
examples/main.gs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from "std" import { fs::{self} };
|
||||||
|
|
||||||
|
fn main {
|
||||||
|
5
|
||||||
|
}
|
111
flake.lock
Normal file
111
flake.lock
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"fenix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687501538,
|
||||||
|
"narHash": "sha256-6uxZWuSoM6rWDPo+7HLCBcNe8+4phnya4qJHS4IlbKo=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "fenix",
|
||||||
|
"rev": "3650022df24f0e5545502439ba7599b786455e2a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "fenix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687171271,
|
||||||
|
"narHash": "sha256-BJlq+ozK2B1sJDQXS3tzJM5a+oVZmi1q0FlBK/Xqv7M=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "abfb11bd1aec8ced1c9bb9adfe68018230f4fb3c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "flake-utils",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687412861,
|
||||||
|
"narHash": "sha256-Z/g0wbL68C+mSGerYS2quv9FXQ1RRP082cAC0Bh4vcs=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "e603dc5f061ca1d8a19b3ede6a8cf9c9fcba6cdc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1663551060,
|
||||||
|
"narHash": "sha256-e2SR4cVx9p7aW/XnVsGsWZBplApA9ZJUjc0fejJhnYo=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "8a5b9ee7b7a2b38267c9481f5c629c015108ab0d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"fenix": "fenix",
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-analyzer-src": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1687460085,
|
||||||
|
"narHash": "sha256-Npfu+4+KpgtZd/JX9wUaV3qP8dwbmoRd4s1NSehwyiE=",
|
||||||
|
"owner": "rust-lang",
|
||||||
|
"repo": "rust-analyzer",
|
||||||
|
"rev": "403433a35559962ad0df91c0ae85ab03e918ba54",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "rust-lang",
|
||||||
|
"ref": "nightly",
|
||||||
|
"repo": "rust-analyzer",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
34
flake.nix
Normal file
34
flake.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
inputs = { fenix.url = "github:nix-community/fenix"; };
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils, fenix }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [ fenix.overlays.default ];
|
||||||
|
};
|
||||||
|
|
||||||
|
toolchain = pkgs.fenix.default;
|
||||||
|
|
||||||
|
flakePkgs = rec { beng = pkgs.callPackage ./. { inherit toolchain; }; };
|
||||||
|
in rec {
|
||||||
|
packages = flake-utils.lib.flattenTree flakePkgs;
|
||||||
|
defaultPackage = packages.beng;
|
||||||
|
|
||||||
|
devShell = pkgs.mkShell {
|
||||||
|
inputsFrom = with packages; [ beng ];
|
||||||
|
|
||||||
|
packages = (with pkgs; [
|
||||||
|
cargo-watch
|
||||||
|
cargo-deny
|
||||||
|
cargo-edit
|
||||||
|
cargo-expand
|
||||||
|
pijul
|
||||||
|
|
||||||
|
# Get the nightly version of rustfmt so we can wrap comments
|
||||||
|
pkgs.fenix.default.rustfmt
|
||||||
|
]) ++ (with toolchain; [ cargo clippy rustc rustfmt ]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
max_width = 100
|
max_width = 80
|
||||||
|
tab_spaces = 2
|
||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
|
|
139
src/ast.rs
139
src/ast.rs
|
@ -1,62 +1,125 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
pub decls: Vec<Decl>,
|
pub(crate) items: Vec<Item>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Range
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Loc(usize, usize);
|
||||||
|
|
||||||
|
impl Loc {
|
||||||
|
pub fn new(left: usize, right: usize) -> Self {
|
||||||
|
Loc(left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// Items
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Item {
|
||||||
|
pub(crate) kind: ItemKind,
|
||||||
|
pub(crate) loc: Loc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Decl {
|
pub enum ItemKind {
|
||||||
Mod(Mod),
|
Import(Import),
|
||||||
Func(Func),
|
FuncDef(FuncDef),
|
||||||
|
StructDef(StructDef),
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// Import
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Import {
|
||||||
|
pub(crate) from: String,
|
||||||
|
pub(crate) items: ImportItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Mod {
|
pub enum ImportItem {
|
||||||
pub name: Ident,
|
SelfItem(Option<String>),
|
||||||
pub decls: Vec<Decl>,
|
Item(String, Option<String>),
|
||||||
|
Module(String, Vec<ImportItem>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// Functions
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FuncDef {
|
||||||
|
pub(crate) name: Option<String>,
|
||||||
|
pub(crate) body: Expr,
|
||||||
|
pub(crate) loc: Loc,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// Structs
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StructDef {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// Expr
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Expr {
|
||||||
|
pub(crate) kind: ExprKind,
|
||||||
|
pub(crate) loc: Loc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Func {
|
pub enum ExprKind {
|
||||||
pub name: Ident,
|
// Literals / primitives
|
||||||
pub args: Vec<Arg>,
|
Literal(Literal),
|
||||||
pub stmts: Vec<Stmt>,
|
|
||||||
pub ret: Option<Expr>,
|
// More copmlex expressionsj
|
||||||
|
BinOp(Box<Expr>, BinOp, Box<Expr>),
|
||||||
|
|
||||||
|
Sequence(Sequence),
|
||||||
|
Paren(Box<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Arg {
|
pub struct Sequence {
|
||||||
pub name: Ident,
|
pub(crate) stmts: Vec<Stmt>,
|
||||||
pub ty: Type,
|
pub(crate) inner: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stmts
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Stmt {
|
||||||
|
pub(crate) kind: StmtKind,
|
||||||
|
pub(crate) loc: Loc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Stmt {
|
pub enum StmtKind {
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
Return(Expr),
|
}
|
||||||
Let(Ident, Expr),
|
|
||||||
|
// ===============================================
|
||||||
|
// Literals
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Literal {
|
||||||
|
pub(crate) kind: LiteralKind,
|
||||||
|
pub(crate) loc: Loc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Expr {
|
pub enum LiteralKind {
|
||||||
Seq(Vec<Stmt>, Box<Expr>),
|
Int(u64),
|
||||||
FuncCall(Ident),
|
|
||||||
Var(Ident),
|
|
||||||
Lit(Lit),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// Random shit
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Lit {
|
pub enum BinOp {
|
||||||
Unit,
|
Plus,
|
||||||
Int(i64),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Type {
|
|
||||||
Unit,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct Ident(pub String);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct Path(pub Vec<Ident>);
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
use cranelift::prelude::*;
|
|
||||||
use cranelift_module::{Linkage, Module};
|
|
||||||
|
|
||||||
use crate::ast::{Decl, Program};
|
|
||||||
|
|
||||||
impl Program {
|
|
||||||
pub fn codegen(&self, mut module: impl Module) -> Result<()> {
|
|
||||||
let mut ctx = module.make_context();
|
|
||||||
|
|
||||||
for decl in self.decls.iter() {
|
|
||||||
match decl {
|
|
||||||
Decl::Func(func) => {
|
|
||||||
let mut builder_ctx = FunctionBuilderContext::new();
|
|
||||||
let mut builder = FunctionBuilder::new(&mut ctx.func, &mut builder_ctx);
|
|
||||||
let entry_block = builder.create_block();
|
|
||||||
builder.append_block_params_for_function_params(entry_block);
|
|
||||||
builder.switch_to_block(entry_block);
|
|
||||||
builder.seal_block(entry_block);
|
|
||||||
|
|
||||||
let int = module.target_config().pointer_type();
|
|
||||||
let val = builder.ins().iconst(int, 12345);
|
|
||||||
builder.ins().return_(&[val]);
|
|
||||||
|
|
||||||
builder.finalize();
|
|
||||||
ctx.func.signature.returns.push(AbiParam::new(int));
|
|
||||||
|
|
||||||
let func_id = module.declare_function(
|
|
||||||
&func.name.0,
|
|
||||||
Linkage::Export,
|
|
||||||
&ctx.func.signature,
|
|
||||||
)?;
|
|
||||||
module.define_function(
|
|
||||||
func_id,
|
|
||||||
&mut ctx,
|
|
||||||
&mut codegen::binemit::NullTrapSink {},
|
|
||||||
)?;
|
|
||||||
module.clear_context(&mut ctx);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
67
src/grammar.lalrpop
Normal file
67
src/grammar.lalrpop
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use crate::ast::*;
|
||||||
|
|
||||||
|
grammar;
|
||||||
|
|
||||||
|
pub Program: Program = <items:Item*> => Program {
|
||||||
|
items,
|
||||||
|
};
|
||||||
|
|
||||||
|
Item: Item = {
|
||||||
|
<left:@L> <kind:ItemKind> <right:@R> =>
|
||||||
|
Item { kind, loc: Loc::new(left, right) },
|
||||||
|
};
|
||||||
|
|
||||||
|
ItemKind: ItemKind = {
|
||||||
|
"fn" <funcdef:FuncDef> => ItemKind::FuncDef(funcdef),
|
||||||
|
};
|
||||||
|
|
||||||
|
FuncDef: FuncDef =
|
||||||
|
<left:@L> <ident:Ident> <body:BlockExpr> <right:@R> => FuncDef {
|
||||||
|
name: Some(ident),
|
||||||
|
body,
|
||||||
|
loc: Loc::new(left, right),
|
||||||
|
};
|
||||||
|
|
||||||
|
Expr: Expr =
|
||||||
|
<left:@L> <kind:ExprKind> <right:@R> => Expr {
|
||||||
|
kind,
|
||||||
|
loc: Loc::new(left, right),
|
||||||
|
};
|
||||||
|
|
||||||
|
ExprKind: ExprKind = {
|
||||||
|
<literal:Literal> => ExprKind::Literal(literal),
|
||||||
|
"(" <expr:Expr> ")" => ExprKind::Paren(Box::new(expr)),
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockExpr: Expr =
|
||||||
|
<left:@L> "{" <stmts:StmtSemi*> <expr:Expr> "}" <right:@R> => Expr {
|
||||||
|
kind: ExprKind::Sequence(Sequence {
|
||||||
|
stmts,
|
||||||
|
inner: Box::new(expr),
|
||||||
|
}),
|
||||||
|
loc: Loc::new(left, right),
|
||||||
|
};
|
||||||
|
|
||||||
|
StmtSemi: Stmt =
|
||||||
|
<left:@L> <kind:StmtKind> <right:@R> ";" => Stmt {
|
||||||
|
kind,
|
||||||
|
loc: Loc::new(left, right),
|
||||||
|
};
|
||||||
|
|
||||||
|
StmtKind: StmtKind = {
|
||||||
|
<expr:Expr> => StmtKind::Expr(expr),
|
||||||
|
};
|
||||||
|
|
||||||
|
Literal: Literal =
|
||||||
|
<left:@L> <kind:LiteralKind> <right:@R> => Literal {
|
||||||
|
kind,
|
||||||
|
loc: Loc::new(left, right),
|
||||||
|
};
|
||||||
|
|
||||||
|
LiteralKind: LiteralKind = {
|
||||||
|
r"[0-9]+" => LiteralKind::Int(<>.parse().unwrap()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Random shit
|
||||||
|
|
||||||
|
Ident: String = r"[A-Za-z_]+" => <>.to_owned();
|
74
src/main.rs
74
src/main.rs
|
@ -1,70 +1,38 @@
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod codegen;
|
pub mod typeck;
|
||||||
pub mod name_res;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod type_check;
|
|
||||||
pub mod utils;
|
|
||||||
|
|
||||||
use std::fs::{File, OpenOptions};
|
use std::{path::PathBuf, fs::File, io::Read};
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use cranelift::prelude::*;
|
use lalrpop_util::lalrpop_mod;
|
||||||
use structopt::StructOpt;
|
|
||||||
|
|
||||||
use crate::name_res::Namespaces;
|
lalrpop_mod!(pub grammar);
|
||||||
|
|
||||||
#[derive(StructOpt)]
|
#[derive(Debug, Parser)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
file: PathBuf,
|
input_file: PathBuf,
|
||||||
#[structopt(name = "out", short = "o", default_value = "a.out")]
|
|
||||||
out: PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let opt = Opt::from_args();
|
let opt = Opt::parse();
|
||||||
|
|
||||||
let contents = {
|
let contents = {
|
||||||
let mut file = File::open(&opt.file)?;
|
let mut file = File::open(&opt.input_file)?;
|
||||||
let mut contents = String::new();
|
let mut string = String::new();
|
||||||
file.read_to_string(&mut contents)?;
|
file.read_to_string(&mut string)?;
|
||||||
contents
|
string
|
||||||
};
|
};
|
||||||
|
|
||||||
let parsed = parser::parse(&contents)?;
|
let parser = grammar::ProgramParser::new();
|
||||||
|
|
||||||
|
let tree = parser.parse(&contents);
|
||||||
|
|
||||||
let namespaces = Namespaces::create(parsed);
|
println!("tree: {tree:?}");
|
||||||
let resolved = namespaces.name_resolution();
|
|
||||||
println!("resolved: {:?}", resolved);
|
|
||||||
|
|
||||||
let isa = {
|
// TODO: Distill tree into rules
|
||||||
use std::str::FromStr;
|
|
||||||
use target_lexicon::triple;
|
|
||||||
let builder = settings::builder();
|
|
||||||
let flags = settings::Flags::new(builder);
|
|
||||||
isa::lookup(triple!("x86_64-unknown-linux-gnu"))?.finish(flags)
|
|
||||||
};
|
|
||||||
use cranelift_object::{ObjectBuilder, ObjectModule};
|
|
||||||
let libcall_names = cranelift_module::default_libcall_names();
|
|
||||||
let builder = ObjectBuilder::new(isa, "OSU", libcall_names)?;
|
|
||||||
let mut module = ObjectModule::new(builder);
|
|
||||||
|
|
||||||
// parsed.codegen(&mut module)?;
|
// TODO: Type-checking
|
||||||
|
|
||||||
let product = module.finish();
|
Ok(())
|
||||||
let out = product.emit()?;
|
|
||||||
{
|
|
||||||
let mut open_opt = OpenOptions::new();
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
|
||||||
// open_opt.mode(0o755);
|
|
||||||
}
|
|
||||||
open_opt.create(true).write(true);
|
|
||||||
let mut file = open_opt.open(&opt.out)?;
|
|
||||||
file.write_all(&out)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
152
src/name_res.rs
152
src/name_res.rs
|
@ -1,152 +0,0 @@
|
||||||
//! Name resolution
|
|
||||||
//! ===
|
|
||||||
//!
|
|
||||||
//! This module deals with name resolution, ultimately going from a bunch of
|
|
||||||
//! different files into a single expression tree ready for type-checking.
|
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
use petgraph::{algo, graphmap::DiGraphMap};
|
|
||||||
|
|
||||||
use crate::ast::*;
|
|
||||||
use crate::utils::Id;
|
|
||||||
|
|
||||||
type HDecls = HashMap<Id, HDecl>;
|
|
||||||
type Graph = DiGraphMap<Id, ()>;
|
|
||||||
type Scopes = Vec<HashSet<String>>;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum HDecl {
|
|
||||||
Func(HFunc),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct HFunc {}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct HExpr {}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct HStmt {}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct HType {}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Namespaces {
|
|
||||||
funcs: HashMap<Id, Func>,
|
|
||||||
types: HashMap<Id, Type>,
|
|
||||||
|
|
||||||
hfuncs: HashMap<Id, HFunc>,
|
|
||||||
|
|
||||||
func_names: HashMap<String, Id>,
|
|
||||||
type_names: HashMap<String, Id>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct NamesResolved {
|
|
||||||
pub decls: HashMap<Id, HDecl>,
|
|
||||||
pub visit_order: Vec<HashSet<Id>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Namespaces {
|
|
||||||
pub fn create(program: Program) -> Self {
|
|
||||||
let mut funcs = HashMap::new();
|
|
||||||
let types = HashMap::new();
|
|
||||||
let mut func_names = HashMap::new();
|
|
||||||
let type_names = HashMap::new();
|
|
||||||
|
|
||||||
for decl in program.decls {
|
|
||||||
match decl {
|
|
||||||
Decl::Func(func) => {
|
|
||||||
let id = Id::default();
|
|
||||||
func_names.insert(func.name.0.clone(), id);
|
|
||||||
funcs.insert(id, func);
|
|
||||||
}
|
|
||||||
Decl::Mod(_mod) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Namespaces {
|
|
||||||
funcs,
|
|
||||||
types,
|
|
||||||
hfuncs: HashMap::new(),
|
|
||||||
func_names,
|
|
||||||
type_names,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name_resolution(&self) -> NamesResolved {
|
|
||||||
let mut hdecls = HashMap::new();
|
|
||||||
let mut graph = Graph::new();
|
|
||||||
|
|
||||||
for (id, func) in self.funcs.iter() {
|
|
||||||
walk_func(&mut hdecls, &mut graph, &self, *id, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visit_order = Vec::new();
|
|
||||||
let scc = algo::tarjan_scc(&graph);
|
|
||||||
for group in scc.iter() {
|
|
||||||
let set = group.iter().cloned().collect();
|
|
||||||
visit_order.push(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
NamesResolved {
|
|
||||||
decls: hdecls,
|
|
||||||
visit_order,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk_func(h: &mut HDecls, g: &mut Graph, n: &Namespaces, src: Id, f: &Func) {
|
|
||||||
let mut scopes = Vec::new();
|
|
||||||
scopes.push(HashSet::new());
|
|
||||||
for s in f.stmts.iter() {
|
|
||||||
walk_stmt(g, n, src, &mut scopes, s);
|
|
||||||
}
|
|
||||||
if let Some(ret) = &f.ret {
|
|
||||||
walk_expr(g, n, src, &mut scopes, ret);
|
|
||||||
}
|
|
||||||
scopes.pop();
|
|
||||||
assert!(scopes.is_empty());
|
|
||||||
|
|
||||||
let func = HFunc {};
|
|
||||||
h.insert(src, HDecl::Func(func));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk_stmt(g: &mut Graph, n: &Namespaces, src: Id, sc: &mut Scopes, s: &Stmt) {
|
|
||||||
match s {
|
|
||||||
Stmt::Let(_, e) | Stmt::Expr(e) | Stmt::Return(e) => walk_expr(g, n, src, sc, e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk_expr(g: &mut Graph, n: &Namespaces, src: Id, sc: &mut Scopes, e: &Expr) {
|
|
||||||
match e {
|
|
||||||
Expr::FuncCall(id) | Expr::Var(id) => {
|
|
||||||
let id = &id.0;
|
|
||||||
let mut found = false;
|
|
||||||
for scope in sc.iter().rev() {
|
|
||||||
if scope.contains(id) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
if let Some(target_id) = n.func_names.get(id) {
|
|
||||||
g.add_node(src);
|
|
||||||
g.add_node(*target_id);
|
|
||||||
g.add_edge(src, *target_id, ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::Seq(stmts, e) => {
|
|
||||||
sc.push(HashSet::new());
|
|
||||||
for s in stmts {
|
|
||||||
walk_stmt(g, n, src, sc, s);
|
|
||||||
}
|
|
||||||
walk_expr(g, n, src, sc, e);
|
|
||||||
sc.pop();
|
|
||||||
}
|
|
||||||
Expr::Lit(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
use crate::ast::*;
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub Program: Program = {
|
|
||||||
<decls:Decls> => { Program { decls } }
|
|
||||||
};
|
|
||||||
|
|
||||||
Decls: Vec<Decl> = Decl*;
|
|
||||||
|
|
||||||
Decl: Decl = {
|
|
||||||
"fn" <name:Ident> "(" <args:Sep<Arg, ",">> ")" "{" <stmts:Stmt*> <ret:Expr> "}" => { Decl::Func(Func{ name, args, stmts, ret: Some(ret), }) },
|
|
||||||
"fn" <name:Ident> "(" <args:Sep<Arg, ",">> ")" "{" <stmts:Stmt*> "}" => { Decl::Func(Func{ name, args, stmts, ret: None, }) },
|
|
||||||
};
|
|
||||||
|
|
||||||
Arg: Arg = <name:Ident> ":" <ty:Type> => Arg { name, ty };
|
|
||||||
|
|
||||||
Stmt: Stmt = {
|
|
||||||
<expr:Expr> ";" => Stmt::Expr(expr),
|
|
||||||
"let" <name:Ident> "=" <expr:Expr> ";" => Stmt::Let(name, expr),
|
|
||||||
"return" <expr:Expr> ";" => Stmt::Return(expr),
|
|
||||||
};
|
|
||||||
|
|
||||||
BlockExpr: Expr = "{" <stmts:Stmt*> <expr:Expr> "}" => Expr::Seq(stmts, Box::new(expr));
|
|
||||||
|
|
||||||
Expr: Expr = {
|
|
||||||
<name:Ident> "(" ")" => Expr::FuncCall(name),
|
|
||||||
Ident => Expr::Var(<>),
|
|
||||||
Lit => Expr::Lit(<>),
|
|
||||||
};
|
|
||||||
|
|
||||||
Lit: Lit = {
|
|
||||||
"(" ")" => Lit::Unit,
|
|
||||||
Int => Lit::Int(<>),
|
|
||||||
};
|
|
||||||
|
|
||||||
Type: Type = {
|
|
||||||
"(" ")" => Type::Unit,
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
Ident: Ident = r"[A-Za-z][A-Za-z0-9_]*|_[A-Za-z0-9_]+" => Ident(<>.to_owned());
|
|
||||||
Int: i64 = r"[0-9]+" => <>.parse::<i64>().unwrap();
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
Sep<T, D>: Vec<T> = {
|
|
||||||
<v:Sep1<T, D>*> <e:T?> => match e {
|
|
||||||
None => v,
|
|
||||||
Some(e) => {
|
|
||||||
let mut v = v;
|
|
||||||
v.push(e);
|
|
||||||
v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Sep1<T, D>: T = <t:T> D => t;
|
|
|
@ -1,17 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use crate::ast::Program;
|
|
||||||
|
|
||||||
mod parser {
|
|
||||||
#![allow(unused_braces)]
|
|
||||||
use lalrpop_util::lalrpop_mod;
|
|
||||||
lalrpop_mod!(parser);
|
|
||||||
pub use self::parser::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(s: impl AsRef<str>) -> Result<Program> {
|
|
||||||
let s = s.as_ref().to_owned();
|
|
||||||
let parser = parser::ProgramParser::new();
|
|
||||||
let res = parser.parse(&s).unwrap();
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
//! Type checking
|
|
||||||
//! ===
|
|
||||||
//!
|
|
||||||
//! This module implements a Hindley-Milner based type checker.
|
|
||||||
|
|
||||||
pub fn type_check() {}
|
|
4
src/typeck.rs
Normal file
4
src/typeck.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
use crate::ast::Program;
|
||||||
|
|
||||||
|
pub fn check(ast: Program) {
|
||||||
|
}
|
26
src/utils.rs
26
src/utils.rs
|
@ -1,26 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref N: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An Id is a uniquely generated value, whose implementation is opaque.
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Id(usize);
|
|
||||||
|
|
||||||
impl Default for Id {
|
|
||||||
fn default() -> Self {
|
|
||||||
Id(gen_int())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_int() -> usize {
|
|
||||||
let mut n = N.lock();
|
|
||||||
let res = *n;
|
|
||||||
*n += 1;
|
|
||||||
res
|
|
||||||
}
|
|
13
traits
13
traits
|
@ -1,13 +0,0 @@
|
||||||
trait Foo {
|
|
||||||
fn foo();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Bar impls Foo {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test(f: impl Foo) {
|
|
||||||
}
|
|
||||||
|
|
||||||
x = Bar {}
|
|
||||||
test(x)
|
|
Loading…
Reference in a new issue