Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 10 additions & 18 deletions examples/scripting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,9 @@ mod scripting {

Ok(None)
}
None => {
Err(evalit::RuntimeError::invalid_argument::<String>(
0, &args[0],
))
}
None => Err(evalit::RuntimeError::invalid_argument::<String>(
0, &args[0],
)),
}
}

Expand All @@ -161,11 +159,9 @@ mod scripting {

Ok(None)
}
_ => {
Err(evalit::RuntimeError::invalid_argument::<String>(
0, &args[0],
))
}
_ => Err(evalit::RuntimeError::invalid_argument::<String>(
0, &args[0],
)),
}
}

Expand All @@ -180,11 +176,9 @@ mod scripting {

Ok(None)
}
None => {
Err(evalit::RuntimeError::invalid_argument::<String>(
0, &args[0],
))
}
None => Err(evalit::RuntimeError::invalid_argument::<String>(
0, &args[0],
)),
}
}

Expand All @@ -195,9 +189,7 @@ mod scripting {
Ok(Some(ValueRef::new(self.remote_addr.clone())))
}

_ => {
Err(evalit::RuntimeError::missing_method::<Self>(method))
}
_ => Err(evalit::RuntimeError::missing_method::<Self>(method)),
}
}
}
Expand Down
245 changes: 149 additions & 96 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod lowering;
mod parser;
mod regalloc;
mod semantic;
mod symbol;
mod typing;

use std::collections::HashMap;
Expand All @@ -13,121 +14,158 @@ use std::sync::Arc;
use ir::builder::{InstBuilder, IrBuilder};
use ir::instruction::IrUnit;
use log::debug;
use typing::TypeContext;
use typing::{TypeChecker, TypeContext, TypeError};

use crate::Environment;
use crate::bytecode::{Module, Register};
use ast::syntax::{Span, Type};
use crate::compiler::ast::syntax::Span;
use crate::compiler::symbol::SymbolTable;
use parser::ParseError;

use codegen::Codegen;
use lowering::{ASTLower, SymbolTable};
use semantic::SemanticAnalyzer;
use lowering::ASTLower;
use semantic::{SemanticAnalyzer, SemanticError};

pub fn compile(script: &str, env: &crate::Environment) -> Result<Arc<crate::Module>, CompileError> {
pub fn compile<'i>(
script: &'i str,
env: &crate::Environment,
) -> Result<Arc<crate::Module>, CompileError<'i>> {
Compiler::new().compile(script, env)
}

#[derive(Debug)]
pub enum CompileError {
Parse(ParseError),
Semantics(String),
UndefinedVariable {
name: String,
},
UnknownType {
name: String,
},
TypeMismatch {
expected: Box<Type>,
actual: Box<Type>,
span: Span,
},
TypeInference(String),
TypeCheck(String),
ArgumentCountMismatch {
expected: usize,
actual: usize,
},
NotCallable {
ty: Type,
span: Span,
},
Unreachable,
BreakOutsideLoop {
span: Span,
},
ContinueOutsideLoop {
span: Span,
},
ReturnOutsideFunction {
span: Span,
},
InvalidOperation {
message: String,
},
}

impl CompileError {
pub fn type_mismatch(expected: Type, actual: Type, span: Span) -> Self {
CompileError::TypeMismatch {
#[derive(Debug, Clone, Copy)]
struct LineCol {
line: usize,
col: usize,
}

impl From<(usize, usize)> for LineCol {
fn from(value: (usize, usize)) -> Self {
Self {
line: value.0,
col: value.1,
}
}
}

#[derive(Debug, Clone)]
pub struct CompileError<'i> {
kind: ErrorKind,
span: &'i str,
line_col: LineCol,
}

impl<'i> CompileError<'i> {
pub fn new(input: &'i str, error: ErrorKind) -> Self {
let (line_col, span) = match error.line_col(input) {
Some(line_col) => {
let span = error.span();
(line_col, &input[span.start..span.end])
}
None => (LineCol { line: 0, col: 0 }, &input[0..0]),
};
Self {
kind: error,
span,
expected: Box::new(expected),
actual: Box::new(actual),
line_col,
}
}
}

impl<'i> std::fmt::Display for CompileError<'i> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Error on {}@{:?}, detail: {:?}",
self.span, self.line_col, self.kind
)
}
}

impl<'i> std::error::Error for CompileError<'i> {}

#[derive(Debug, Clone)]
pub enum ErrorKind {
// Io(std::io::Error),
Parse(ParseError),
Type(TypeError),
Semantic(SemanticError),
}

impl ErrorKind {
fn line_col(&self, input: &str) -> Option<LineCol> {
match self {
ErrorKind::Parse(ParseError { span, .. }) => span.line_col(input).map(Into::into),
ErrorKind::Type(TypeError { span, .. }) => span.line_col(input).map(Into::into),
ErrorKind::Semantic(SemanticError { span, .. }) => span.line_col(input).map(Into::into),
}
}

fn span(&self) -> Span {
match self {
ErrorKind::Parse(ParseError { span, .. }) => *span,
ErrorKind::Type(TypeError { span, .. }) => *span,
ErrorKind::Semantic(SemanticError { span, .. }) => *span,
}
}
}

impl From<ParseError> for CompileError {
impl From<ParseError> for ErrorKind {
fn from(error: ParseError) -> Self {
CompileError::Parse(error)
ErrorKind::Parse(error)
}
}

impl std::fmt::Display for CompileError {
impl From<TypeError> for ErrorKind {
fn from(error: TypeError) -> Self {
ErrorKind::Type(error)
}
}

impl From<SemanticError> for ErrorKind {
fn from(error: SemanticError) -> Self {
ErrorKind::Semantic(error)
}
}

impl std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompileError::Parse(error) => write!(f, "Parse error: {error}"),
CompileError::Semantics(message) => write!(f, "Semantics error: {message}"),
CompileError::UndefinedVariable { name } => {
write!(f, "Undefined variable `{name}`")
}
CompileError::UnknownType { name } => {
write!(f, "Unknow type `{name}`")
}
CompileError::TypeMismatch {
expected,
actual,
span,
} => write!(
f,
"Type mismatch: expected `{expected:?}`, actual `{actual:?}` at {span:?}"
),
CompileError::TypeInference(message) => write!(f, "Type inference error: {message}"),
CompileError::TypeCheck(message) => write!(f, "Type check error: {message}"),
CompileError::ArgumentCountMismatch { expected, actual } => write!(
f,
"Argument count mismatch: expected {expected}, actual {actual}"
),
CompileError::NotCallable { ty, span } => {
write!(f, "Not callable: `{ty:?}` at {span:?}")
}
CompileError::Unreachable => write!(f, "Unreachable"),
CompileError::BreakOutsideLoop { span } => write!(f, "Break outside loop at {span:?}"),
CompileError::ContinueOutsideLoop { span } => {
write!(f, "Continue outside loop at {span:?}")
}
CompileError::ReturnOutsideFunction { span } => {
write!(f, "Return outside function at {span:?}")
}
CompileError::InvalidOperation { message } => {
write!(f, "Invalid operation, {message}")
}
ErrorKind::Parse(error) => write!(f, "Parse error: {error}"),
ErrorKind::Type(error) => write!(f, "Type error: {error:?}"),
ErrorKind::Semantic(error) => write!(f, "Semantic error: {error:?}"),
}
}
}

impl std::error::Error for CompileError {}
pub struct FileId(usize);

pub struct Context {
sources: Vec<String>,
}

impl Context {
pub fn new() -> Self {
Self { sources: vec![] }
}

pub fn add_source(&mut self, source: String) -> FileId {
let id = FileId(self.sources.len());
self.sources.push(source);
id
}

// pub fn add_file(&mut self, file: impl AsRef<Path>) -> Result<FileId, CompileError> {
// let id = FileId(self.sources.len());
// let content = std::fs::read_to_string(file.as_ref())?;
// self.sources.push(content);
// Ok(id)
// }

pub fn get_source(&self, file: FileId) -> Option<&str> {
self.sources.get(file.0).map(|s| s.as_str())
}
}

pub struct Compiler {}

Expand All @@ -142,24 +180,39 @@ impl Compiler {
Self {}
}

pub fn compile(&self, input: &str, env: &Environment) -> Result<Arc<Module>, CompileError> {
pub fn compile<'i>(
&self,
input: &'i str,
env: &Environment,
) -> Result<Arc<Module>, CompileError<'i>> {
match self.compile_inner(input, env) {
Ok(module) => Ok(module),
Err(err) => Err(CompileError::new(input, err)),
}
}

fn compile_inner(&self, input: &str, env: &Environment) -> Result<Arc<Module>, ErrorKind> {
// 解析输入
let mut ast = parser::parse_file(input)?;
let ast = parser::parse_file(input)?;

debug!("AST: {ast:?}");

let mut type_cx = TypeContext::new();
type_cx.process_env(env);
type_cx.check_type_def(&ast.stmts)?;

// 语义分析
let mut analyzer = SemanticAnalyzer::new(&mut type_cx);
analyzer.analyze_program(&mut ast, env)?;
let mut analyzer = SemanticAnalyzer::new(&type_cx);
analyzer.analyze_program(&ast, env)?;

// 类型检查
let mut checker = TypeChecker::new(&type_cx);
checker.check_program(&ast, env)?;

// IR生成, AST -> IR
let mut unit = IrUnit::new();
let builder: &mut dyn InstBuilder = &mut IrBuilder::new(&mut unit);
let mut lower = ASTLower::new(builder, SymbolTable::new(), env, &type_cx);
lower.lower_program(ast)?;
lower.lower_program(ast);

// code generation, IR -> bytecode
let mut codegen = Codegen::new(&Register::general());
Expand Down
5 changes: 1 addition & 4 deletions src/compiler/ast/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,8 @@ enum_item = { "enum" ~ identifier ~ "{" ~ (enum_item_list ~ ","?)? ~ "}" }

enum_item_list = { enum_field ~ ("," ~ enum_field)* }

enum_field = { simple_enum_field | tuple_enum_field }
enum_field = { identifier ~ ("(" ~ type_expression ~ ")")?}

simple_enum_field = { identifier ~ !"(" }

tuple_enum_field = { identifier ~ "(" ~ type_expression ~ ("," ~ type_expression)* ~ ")" }

/// Expression Statment
expression_statement = { expression ~ ";" }
Expand Down
Loading