wip: more work on the compiler. I think I went the wrong direction.

This commit is contained in:
James Harton 2022-08-14 07:11:42 +12:00
parent 2efe1a3cf1
commit f6eccebb27
9 changed files with 442 additions and 39 deletions

View file

@ -30,3 +30,9 @@ impl<T: Debug> IndexedVec<T> {
#[derive(Debug, Clone, Copy)]
pub struct IndexedVecKey<T: Debug>(usize, PhantomData<T>);
impl<T: Debug> From<IndexedVecKey<T>> for usize {
fn from(key: IndexedVecKey<T>) -> Self {
key.0
}
}

View file

@ -29,19 +29,19 @@ impl<T: Debug> UniqueVec<T> {
self.data.get(key.0)
}
pub fn find_by<F>(&self, pred: F) -> Option<UniqueVecKey<T>>
pub fn find_by<F>(&self, predicate: F) -> Option<UniqueVecKey<T>>
where
F: Fn(&T) -> bool,
{
self.data
.iter()
.position(pred)
.position(predicate)
.map(|i| UniqueVecKey(i, PhantomData))
}
pub fn replace(&mut self, key: UniqueVecKey<T>, value: T) {
let elem = self.data.get_mut(key.0).unwrap();
*elem = value;
let element = self.data.get_mut(key.0).unwrap();
*element = value;
}
pub fn into_vec(self) -> Vec<T> {

View file

@ -1,14 +1,18 @@
use crate::instructions::Instruction;
use crate::module::{Module, StringKey, TypeKey};
use crate::module::{BlockKey, Module, StringKey, TypeKey};
#[derive(Debug)]
pub struct Builder<'a> {
module: &'a mut Module,
block: BlockKey,
}
impl<'a> Builder<'a> {
pub fn new(module: &'a mut Module) -> Builder<'a> {
Builder { module }
pub fn new(module: &'a mut Module, block: Option<BlockKey>) -> Builder<'a> {
let block = block
.unwrap_or(module.current_block.peek().unwrap().clone())
.clone();
Builder { module, block }
}
pub fn push_atom(&mut self, value: StringKey) {
@ -36,8 +40,21 @@ impl<'a> Builder<'a> {
self.push_instruction(Instruction::PushString(value.into()));
}
pub fn jump(&mut self, target: BlockKey) {
self.push_instruction(Instruction::Jump(target.into()));
}
pub fn jump_if_true(&mut self, target: BlockKey) {
self.push_instruction(Instruction::JumpIfTrue(target.into()));
}
fn push_instruction(&mut self, inst: Instruction) {
let block = self.module.current_block_mut();
let block_id = self.block.clone();
let block = self
.module
.blocks
.get_mut(block_id.clone())
.expect(&format!("Unable to get block {:?}", block_id));
block.push_instruction(inst);
}
}

View file

@ -38,3 +38,21 @@ impl From<(&Path, outrun_parser::Error)> for Error {
}
}
}
impl From<outrun_lexer::Error> for Error {
fn from(error: outrun_lexer::Error) -> Error {
Error {
kind: ErrorKind::Lex(error),
file: "unknown".to_string(),
}
}
}
impl From<outrun_parser::Error> for Error {
fn from(error: outrun_parser::Error) -> Error {
Error {
kind: ErrorKind::Parse(error),
file: "unknown".to_string(),
}
}
}

View file

@ -6,4 +6,6 @@ pub enum Instruction {
PushFloat(f64),
PushInteger(i64),
PushString(usize),
Jump(usize),
JumpIfTrue(usize),
}

View file

@ -2,18 +2,23 @@ extern crate outrun_common;
extern crate outrun_lexer;
extern crate outrun_parser;
use outrun_lexer::TokenKind;
use outrun_parser::{Node, NodeKind, NodeValue};
use std::collections::HashMap;
use std::path::Path;
mod block;
mod builder;
mod error;
mod instructions;
mod message;
mod module;
use builder::Builder;
pub use error::Error;
pub use module::Module;
pub use module::{BlockKey, Module, StringKey, TypeKey};
use crate::block::Block;
pub fn compile_file(path: &Path) -> Result<(), Error> {
println!("*** Compiling file: {}", path.to_str().unwrap());
@ -24,39 +29,317 @@ pub fn compile_file(path: &Path) -> Result<(), Error> {
let mut module = Module::new(Some(path.to_str().unwrap()));
for node in nodes {
visit(node, &mut module);
visit(&node, &mut module);
}
println!("MODULE: {:?}", module);
Ok(())
}
fn visit(node: Node, module: &mut Module) {
pub fn compile_string(input: &str) -> Result<(), Error> {
let nodes = outrun_lexer::lex_string(input)
.map_err(Error::from)
.and_then(|tokens| outrun_parser::parse(&tokens).map_err(|e| Error::from(e)))?;
let mut module = Module::new::<String>(None);
for node in nodes {
visit(&node, &mut module);
}
println!("MODULE: {:#?}", module);
Ok(())
}
fn visit(node: &Node, mut module: &mut Module) {
match node.kind {
NodeKind::Atom => {
let atom = module.strings.insert(node.value.as_string().unwrap());
Builder::new(module).push_atom(atom);
Builder::new(module, None).push_atom(atom);
}
NodeKind::Block => {
for node in node.value.as_nodes().unwrap() {
visit(&node, &mut module);
}
}
NodeKind::Boolean => {
let value = node.value.as_bool().unwrap();
Builder::new(module).push_boolean(value);
Builder::new(module, None).push_boolean(value);
}
NodeKind::Constant => {
let value = module.reference_type(node.value.as_string().unwrap());
Builder::new(module).push_constant(value);
Builder::new(module, None).push_constant(value);
}
NodeKind::Definition => {
match node.value.clone() {
// NodeValue::Definition { kind: TokenKind::KeywordStruct, .. } => visit_struct(node, module),
NodeValue::Definition {
kind: TokenKind::KeywordProtocol,
name,
fields,
arguments,
result,
} => visit_protocol(name, fields, arguments, result, module),
// NodeValue::Definition { kind: TokenKind::KeywordImpl,.. } => visit_impl(node, module),
NodeValue::Definition {
kind: TokenKind::KeywordDef,
name,
fields,
arguments,
result,
} => visit_def(name, fields, arguments, result, module),
NodeValue::Definition {
kind: TokenKind::KeywordDefPrivate,
name,
fields,
arguments,
result,
} => visit_defp(name, fields, arguments, result, module),
NodeValue::Definition {
kind: TokenKind::KeywordDefStatic,
name,
fields,
arguments,
result,
} => visit_defs(name, fields, arguments, result, module),
_ => panic!("NOT A PROTOCOL"),
}
}
NodeKind::Documentation => {
let value = node.value.as_string().unwrap();
let key = module.strings.insert(value);
module.current_doc = Some(key);
}
NodeKind::Float => {
let value = node.value.as_float().unwrap();
Builder::new(module).push_float(value);
Builder::new(module, None).push_float(value);
}
NodeKind::Integer => {
let value = node.value.as_integer().unwrap();
Builder::new(module).push_integer(value);
Builder::new(module, None).push_integer(value);
}
NodeKind::String => {
let value = node.value.as_string().unwrap();
Builder::new(module).push_string(value);
Builder::new(module, None).push_string(value);
}
NodeKind::Module => {
for node in node.value.as_nodes().unwrap() {
visit(node, &mut module);
}
}
_ => panic!("Can't handle: {:#?}", node),
}
}
fn visit_protocol(
name: Box<Node>,
fields: Vec<Node>,
arguments: Vec<Node>,
result: Option<Box<Node>>,
mut module: &mut Module,
) {
let name = eval_constant_name(&name);
if !fields.is_empty() {
let span = fields
.first()
.unwrap()
.span
.extend(fields.last().unwrap().span);
module.warning("Protocol definitions do not have fields", span);
}
if let Some(result) = result {
module.warning("Protocol definitions do no have return types", result.span);
}
let mut arguments = deconstruct_keyword_list(&arguments);
let requires = arguments
.remove("requires")
.map(|node| eval_type_expr_to_keys(node, &mut module))
.unwrap_or_else(|| vec![]);
let protocol_type = module.new_protocol_type(Some(name), requires, module.current_doc.clone());
module.current_doc = None;
module
.current_definition
.push(protocol_type.clone())
.unwrap();
let body = arguments.remove("as");
for (key, node) in arguments.iter() {
module.warning(&format!("Unknown protocol argument {}", key), node.span);
}
if let Some(body) = body {
visit(body, &mut module);
}
module.current_definition.pop().unwrap();
println!("defining protocol: {:?}", protocol_type);
println!(" => body: {:#?}", body);
}
fn visit_def(
name: Box<Node>,
fields: Vec<Node>,
arguments: Vec<Node>,
result: Option<Box<Node>>,
module: &mut Module,
) {
let name = name.value.as_string().unwrap();
println!("def {:#?}", name);
let fields = deconstruct_keyword_list(&fields)
.iter()
.map(|(key, value)| {
let arg_type_keys = eval_type_expr_to_keys(value, module);
let arg_type = module.new_protocol_type::<String>(None, arg_type_keys, None);
let string_key = module.strings.insert(key.to_string());
(string_key, arg_type)
})
.collect::<Vec<(StringKey, TypeKey)>>();
let return_type = result
.map(|node| {
let result_keys = eval_type_expr_to_keys(&node, module);
module.new_protocol_type::<String>(None, result_keys, None)
})
.unwrap();
module.push_function(name, &fields, return_type);
let mut arguments = deconstruct_keyword_list(&arguments);
let entry_block = module.current_block.peek().cloned().unwrap();
let body_block = module.push_block();
if let Some(guard) = arguments.remove("guard") {
visit(guard, module);
let mut builder = Builder::new(module, Some(entry_block));
builder.jump_if_true(body_block);
} else {
let mut builder = Builder::new(module, Some(entry_block));
builder.jump(body_block);
}
if let Some(body) = arguments.remove("as") {
visit(body, module);
}
module.pop_block();
module.pop_function();
}
fn visit_defp(
name: Box<Node>,
fields: Vec<Node>,
arguments: Vec<Node>,
result: Option<Box<Node>>,
module: &mut Module,
) {
let name = name.value.as_string().unwrap();
println!("defp {:#?}", name);
}
fn visit_defs(
name: Box<Node>,
fields: Vec<Node>,
arguments: Vec<Node>,
result: Option<Box<Node>>,
module: &mut Module,
) {
let name = name.value.as_string().unwrap();
println!("defs {:#?}", name);
}
fn eval_constant_name(node: &Node) -> String {
match node.kind {
NodeKind::Constant => node.value.as_string().unwrap(),
NodeKind::Infix => match node.value {
NodeValue::Infix(ref lhs, TokenKind::Dot, ref rhs) => {
let lhs = eval_constant_name(lhs);
let rhs = eval_constant_name(rhs);
format!("{}.{}", lhs, rhs)
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}
fn eval_type_expr(node: &Node, mut output: Vec<String>) -> Vec<String> {
match node.kind {
NodeKind::Constant => {
output.push(node.value.as_string().unwrap());
return output;
}
NodeKind::Infix => match node.value {
NodeValue::Infix(ref lhs, TokenKind::Plus, ref rhs) => {
let output = eval_type_expr(lhs, output);
let output = eval_type_expr(rhs, output);
return output;
}
NodeValue::Infix(ref lhs, TokenKind::Dot, ref rhs) => {
let lhs = eval_constant_name(lhs);
let rhs = eval_constant_name(rhs);
output.push(format!("{}.{}", lhs, rhs));
return output;
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}
fn eval_type_expr_to_keys(node: &Node, module: &mut Module) -> Vec<TypeKey> {
eval_type_expr(node, vec![])
.iter()
.map(|type_name| module.reference_type(type_name))
.collect()
}
fn deconstruct_keyword_list(keyword_list: &[Node]) -> HashMap<&str, &Box<Node>> {
keyword_list
.iter()
.filter_map(|node| match node.value {
NodeValue::KeywordPair(ref key, ref value) => {
let key = key.value.as_str().unwrap();
Some((key, value))
}
_ => None,
})
.collect::<HashMap<&str, &Box<Node>>>()
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_protocol() {
let source = r#"
```doc
# Boolean
Provides a common interface for values masquerading as Booleans.
```
protocol Boolean, requires: Fruit.Bats + Vampire.Bats, as: do
```doc
A mechanism for values to convert themselves into a concrete boolean value.
Must be implemented.
```
def true?(self: Self): Outrun.Core.Boolean
```doc
Is the value false?
```
def false?(self: Self): Outrun.Core.Boolean, as: !true?(self)
end
"#;
compile_string(&source);
assert!(false);
}
}

View file

@ -0,0 +1,40 @@
use outrun_lexer::Span;
#[derive(Debug)]
pub enum MessageSeverity {
Info,
Warning,
Error,
}
#[derive(Debug)]
pub struct Message {
message: String,
severity: MessageSeverity,
span: Span,
}
impl Message {
pub fn info<T: ToString>(message: T, span: Span) -> Message {
Message {
message: message.to_string(),
severity: MessageSeverity::Info,
span,
}
}
pub fn warning<T: ToString>(message: T, span: Span) -> Message {
Message {
message: message.to_string(),
severity: MessageSeverity::Warning,
span,
}
}
pub fn error<T: ToString>(message: T, span: Span) -> Message {
Message {
message: message.to_string(),
severity: MessageSeverity::Error,
span,
}
}
}

View file

@ -1,21 +1,27 @@
use crate::block::Block;
use crate::message::Message;
use outrun_common::indexed_vec::{IndexedVec, IndexedVecKey};
use outrun_common::stack::Stack;
use outrun_common::unique_vec::{UniqueVec, UniqueVecKey};
use outrun_lexer::Span;
use std::collections::HashMap;
pub type TypeKey = UniqueVecKey<Type>;
pub type BlockKey = IndexedVecKey<Block>;
pub type StringKey = UniqueVecKey<String>;
#[derive(Debug)]
pub struct Module {
pub strings: UniqueVec<String>,
location: Option<StringKey>,
blocks: IndexedVec<Block>,
pub(crate) blocks: IndexedVec<Block>,
functions: HashMap<StringKey, Function>,
current_block: Stack<IndexedVecKey<Block>>,
pub(crate) current_block: Stack<IndexedVecKey<Block>>,
current_function: Stack<StringKey>,
types: UniqueVec<Type>,
messages: Vec<Message>,
pub current_doc: Option<StringKey>,
pub current_definition: Stack<TypeKey>,
}
impl Module {
@ -28,6 +34,9 @@ impl Module {
let current_block = Stack::new();
let current_function = Stack::new();
let types = UniqueVec::new(|l: &Type, r: &Type| l.name() == r.name());
let messages = Vec::new();
let current_doc = None;
let current_definition = Stack::new();
Module {
strings,
@ -37,9 +46,24 @@ impl Module {
current_block,
current_function,
types,
messages,
current_doc,
current_definition,
}
}
pub fn info<T: ToString>(&mut self, message: T, span: Span) {
self.messages.push(Message::info(message, span));
}
pub fn warning<T: ToString>(&mut self, message: T, span: Span) {
self.messages.push(Message::warning(message, span));
}
pub fn error<T: ToString>(&mut self, message: T, span: Span) {
self.messages.push(Message::error(message, span));
}
pub fn push_function<T: ToString>(
&mut self,
name: T,
@ -68,13 +92,17 @@ impl Module {
self.current_function.pop().ok()
}
pub fn push_block(&mut self) -> IndexedVecKey<Block> {
pub fn push_block(&mut self) -> BlockKey {
let block = Block::new();
let block_id = self.blocks.insert(block);
self.current_block.push(block_id.clone()).unwrap();
block_id
}
pub fn pop_block(&mut self) -> Option<BlockKey> {
self.current_block.pop().ok()
}
pub fn current_block_mut(&mut self) -> &mut Block {
let block_id = self.current_block.peek().unwrap();
self.blocks.get_mut(block_id.clone()).unwrap()
@ -99,17 +127,17 @@ impl Module {
&mut self,
name: Option<T>,
requirements: Vec<TypeKey>,
docs: Option<StringKey>,
) -> TypeKey {
let name = name
.map(|s| s.to_string())
.or_else(|| {
Some(
requirements
.iter()
.map(|k| self.name_of(k.clone()))
.collect::<Vec<&str>>()
.join("+"),
)
let mut requirements = requirements
.iter()
.map(|k| self.name_of(k.clone()))
.collect::<Vec<&str>>();
requirements.sort();
Some(requirements.join("+"))
})
.map(|s| self.strings.insert(s))
.unwrap();
@ -117,6 +145,7 @@ impl Module {
let new_type = Type::Protocol {
name: name.clone(),
requirements,
docs,
};
if let Some(key) = self.types.find_by(|t| t.name() == name) {
@ -125,13 +154,18 @@ impl Module {
self.types.replace(key.clone(), new_type);
return key;
}
panic!("Attempt to overwrite existing type {:#?}", r#type);
panic!("Attempt to overwrite existing type {:#?}", (r#type, name));
}
self.types.insert(new_type)
}
pub fn new_struct_type<T: ToString>(&mut self, name: T, fields: Vec<(T, TypeKey)>) -> TypeKey {
pub fn new_struct_type<T: ToString>(
&mut self,
name: T,
fields: Vec<(T, TypeKey)>,
docs: Option<StringKey>,
) -> TypeKey {
let name = self.strings.insert(name.to_string());
let (field_names, field_types) = fields.iter().fold(
(Vec::new(), Vec::new()),
@ -146,6 +180,7 @@ impl Module {
name: name.clone(),
field_names,
field_types,
docs,
};
if let Some(key) = self.types.find_by(|t| t.name() == name) {
@ -191,10 +226,12 @@ pub enum Type {
name: StringKey,
field_names: Vec<StringKey>,
field_types: Vec<TypeKey>,
docs: Option<StringKey>,
},
Protocol {
name: StringKey,
requirements: Vec<TypeKey>,
docs: Option<StringKey>,
},
Integer(StringKey),
Boolean(StringKey),

View file

@ -36,14 +36,14 @@ fn collect_files(path: &Path, mut files: Vec<PathBuf>) -> Result<Vec<PathBuf>, E
Ok(files)
}
#[cfg(test)]
mod test {
use super::*;
// #[cfg(test)]
// mod test {
// use super::*;
#[test]
fn test_init() {
let result = init().unwrap();
println!("result: {:?}", result);
assert!(false);
}
}
// #[test]
// fn test_init() {
// let result = init().unwrap();
// println!("result: {:?}", result);
// assert!(false);
// }
// }