Grand renaming of things

This commit is contained in:
greg 2017-08-29 00:28:19 -07:00
parent 801896bcc6
commit dd22ca0291
18 changed files with 243 additions and 223 deletions

View File

@ -1,7 +1,11 @@
Schala
======
## The experimental programming language meta-interpreter
TODO:
-null-only language should be called Maaru
-haskell-ish langauge should be called Robo
-typeful scripting language should be called schala
rename accordingly!
# Schala - a programming language meta-interpreter
Schala is a Rust-language framework written to make it easy to
create and experiment with toy programming languages. It provides
@ -10,34 +14,47 @@ for tokenizing text, parsing tokens, evaluating an abstract syntax tree,
and other tasks that are common to all programming languages.
Schala started out life as an experiment in writing a Javascript-like
programming language that would never encounter any kind of runtime
value error, but rather always return `null` under any kind of error
condition. I had seen one too many Javascript `Uncaught TypeError:
Cannot read property ___ of undefined` messages, and I was a bit frustrated.
Plus I had always wanted to write a programming langauge from scratch,
and Rust is a fun language to program in.
programming language that would never encounter any kind of runtime value
error, but rather always return `null` under any kind of error condition. I had
seen one too many Javascript `Uncaught TypeError: Cannot read property ___ of
undefined` messages, and I was a bit frustrated. Plus I had always wanted to
write a programming langauge from scratch, and Rust is a fun language to
program in. Over time I became interested in playing around with other sorts
of programming languages as well, and wanted to make the process as general as
possible.
Over time I became interested in playing around with other sorts
of programming languages as well, and wanted to make the process
as general as possible. I changed the name of the project to
Schala, after the Princess of Zeal from *Chrono Trigger*, because I
like classic JRPGs and because it sounds sort of like Scala.
The name of the project comes from Schala the Princess of Zeal from the 1995
SNES RPG *Chrono Trigger*. I like classic JRPGs and enjoyed the thought of
creating a language name confusingly close to Scala. The naming scheme for
languages implemented with the Schala meta-interpreter is Chrono Trigger
characters.
Schala is as yet an incomplete personal project that I continue to work
on as my time permits.
## Languages implemented using the meta-interpreter
### Reference works
* The eponymous *Schala* language is an interpreted/compiled scripting langauge,
designed to be relatively simple, but with a reasonably sophisticated type
system.
* *Maaru* was the original Schala (since renamed to free up the name *Schala*
for the above language), a very simple dynamically-typed scripting language
such that all possible runtime errors result in null rather than program
failure.
* *Robo* is an experiment in creating a lazy, functional, strongly-typed language
much like Haskell
## Reference works
Here's a partial list of resources I've made use of in the process
of learning how to write a programming language.
#### Evaluation
### Evaluation
*Understanding Computation*, Tom Stuart, O'Reilly 2013
#### Parsing
### Parsing
http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
[Crafting Interpreters](http://www.craftinginterpreters.com/)
#### LLVM
### LLVM
http://blog.ulysse.io/2016/07/03/llvm-getting-started.html

View File

@ -5,7 +5,7 @@ use std::collections::HashMap;
use self::llvm_sys::prelude::*;
use self::llvm_sys::{LLVMIntPredicate, LLVMRealPredicate};
use schala_lang::parser::{AST, Statement, Function, Prototype, Expression, BinOp};
use maaru_lang::parser::{AST, Statement, Function, Prototype, Expression, BinOp};
use language::LLVMCodeString;
use llvm_wrap as LLVMWrap;

View File

@ -2,13 +2,13 @@ extern crate take_mut;
use std::collections::HashMap;
use std::collections::VecDeque;
use schala_lang::parser::{AST, Statement, Expression, Function, Callable, BinOp};
use maaru_lang::parser::{AST, Statement, Expression, Function, Callable, BinOp};
use std::rc::Rc;
use std::io::{Write, Stdout, BufWriter};
use std::convert::From;
use schala_lang::parser::Expression::*;
use schala_lang::parser::Statement::*;
use maaru_lang::parser::Expression::*;
use maaru_lang::parser::Statement::*;
type Reduction<T> = (T, Option<SideEffect>);

View File

@ -1,157 +1,44 @@
extern crate itertools;
use self::itertools::Itertools;
use ::std::marker::PhantomData;
pub mod tokenizer;
pub mod parser;
pub mod eval;
pub mod compilation;
use language::{ProgrammingLanguage, EvaluationMachine, ParseError, TokenError, LLVMCodeString};
pub struct Maaru {
}
pub use self::eval::Evaluator as MaaruEvaluator;
impl Maaru {
pub fn new() -> Maaru {
Maaru { }
pub struct Maaru<'a> { marker: PhantomData<&'a ()> }
impl<'a> Maaru<'a> {
pub fn new() -> Maaru <'a> {
Maaru { marker: PhantomData }
}
}
pub struct MaaruEvaluator {
pub trace_evaluation: bool,
}
#[derive(Debug)]
pub enum Token {
StrLiteral(String),
Backtick,
Newline,
LParen,
RParen,
LBracket,
RBracket,
LBrace,
RBrace,
Period,
Comma,
Colon,
Semicolon,
SingleQuote,
Identifier(String),
Operator(String),
NumLiteral(Number),
}
#[derive(Debug)]
pub enum Number {
IntegerRep(String),
FloatRep(String)
}
pub type AST = Vec<ASTNode>;
#[derive(Debug)]
pub enum ASTNode {
FunctionDefinition(String, Expression),
ImportStatement(String),
}
#[derive(Debug)]
pub enum Expression {
}
impl ProgrammingLanguage for Maaru {
type Token = Token;
type AST = AST;
type Evaluator = MaaruEvaluator;
impl<'a> ProgrammingLanguage for Maaru<'a> {
type Token = tokenizer::Token;
type AST = parser::AST;
type Evaluator = MaaruEvaluator<'a>;
fn name() -> String {
"Maaru".to_string()
}
fn tokenize(input: &str) -> Result<Vec<Self::Token>, TokenError> {
use self::Token::*;
let mut tokens = Vec::new();
let mut iter = input.chars().peekable();
while let Some(c) = iter.next() {
if c == ';' {
while let Some(c) = iter.next() {
if c == '\n' {
break;
}
}
continue;
}
let cur_tok = match c {
c if char::is_whitespace(c) && c != '\n' => continue,
'\n' => Newline,
'(' => LParen,
')' => RParen,
'[' => LBracket,
']' => RBracket,
'{' => LBrace,
'}' => RBrace,
',' => Comma,
':' => Colon,
';' => Semicolon,
'.' => Period,
'`' => Backtick,
'\'' => SingleQuote,
'"' => {
let mut buffer = String::new();
loop {
match iter.next() {
Some(x) if x == '"' => break,
Some(x) => buffer.push(x),
None => return Err(TokenError::new("Unclosed quote")),
}
}
StrLiteral(buffer)
}
c if c.is_digit(10) => {
let mut integer = true;
let mut buffer = String::new();
buffer.push(c);
buffer.extend(iter.peeking_take_while(|x| x.is_digit(10)));
if let Some(&'.') = iter.peek() {
buffer.push(iter.next().unwrap());
integer = false;
}
buffer.extend(iter.peeking_take_while(|x| x.is_digit(10)));
let inner = if integer {
Number::IntegerRep(buffer)
} else {
Number::FloatRep(buffer)
};
NumLiteral(inner)
},
c if char::is_alphanumeric(c) => {
let mut buffer = String::new();
buffer.push(c);
buffer.extend(iter.peeking_take_while(|x| char::is_alphanumeric(*x)));
Identifier(buffer)
},
c => {
let mut buffer = String::new();
buffer.push(c);
buffer.extend(iter.peeking_take_while(|x| !char::is_whitespace(*x)));
Operator(buffer)
}
};
tokens.push(cur_tok);
}
Ok(tokens)
tokenizer::tokenize(input)
}
fn parse(_input: Vec<Self::Token>) -> Result<Self::AST, ParseError> {
Ok(vec!())
fn parse(input: Vec<Self::Token>) -> Result<Self::AST, ParseError> {
parser::parse(&input, &[]).map_err(|x| ParseError { msg: x.msg })
}
fn evaluate(_ast: Self::AST, _evaluator: &mut Self::Evaluator) -> Vec<String> {
vec!["Unimplemented".to_string()]
fn evaluate(ast: Self::AST, evaluator: &mut Self::Evaluator) -> Vec<String> {
evaluator.run(ast)
}
fn compile(_ast: Self::AST) -> LLVMCodeString {
unimplemented!()
fn compile(ast: Self::AST) -> LLVMCodeString {
compilation::compile_ast(ast)
}
}
impl EvaluationMachine for MaaruEvaluator {
impl<'a> EvaluationMachine for MaaruEvaluator<'a> {
fn set_option(&mut self, option: &str, value: bool) -> bool {
if option == "trace_evaluation" {
self.trace_evaluation = value;
@ -161,9 +48,7 @@ impl EvaluationMachine for MaaruEvaluator {
false
}
fn new() -> MaaruEvaluator {
MaaruEvaluator {
trace_evaluation: false,
}
fn new() -> MaaruEvaluator<'a> {
MaaruEvaluator::new(None)
}
}

View File

@ -1,5 +1,5 @@
use schala_lang::tokenizer::{Token, Kw, OpTok};
use schala_lang::tokenizer::Token::*;
use maaru_lang::tokenizer::{Token, Kw, OpTok};
use maaru_lang::tokenizer::Token::*;
use std::fmt;
use std::collections::VecDeque;

View File

@ -9,11 +9,14 @@ use std::process;
use std::io::Write;
use std::default::Default;
/*
mod schala_lang;
use schala_lang::SchalaEvaluator;
use schala_lang::Schala;
*/
mod maaru_lang;
mod robo_lang;
mod language;
use language::{ProgrammingLanguage, LanguageInterface, LLVMCodeString, EvaluationMachine};
@ -26,8 +29,8 @@ use virtual_machine::{run_vm, run_assembler};
fn main() {
let languages: Vec<Box<LanguageInterface>> =
vec![
Box::new((Schala::new(), SchalaEvaluator::new(None))),
Box::new((maaru_lang::Maaru::new(), maaru_lang::MaaruEvaluator::new())),
Box::new((maaru_lang::Maaru::new(), maaru_lang::MaaruEvaluator::new(None))),
Box::new((robo_lang::Robo::new(), robo_lang::RoboEvaluator::new())),
];
let option_matches =
@ -79,7 +82,7 @@ fn main() {
repl.run();
}
[_, ref filename, _..] => {
let language = Schala::new();
let language = maaru_lang::Maaru::new();
run_noninteractive(filename, &language, trace_evaluation, compile);
}
};
@ -308,7 +311,7 @@ pub fn compilation_sequence(llvm_code: LLVMCodeString, sourcefile: &str) {
let obj_filename = "out.o";
let q: Vec<&str> = sourcefile.split('.').collect();
let bin_filename = match &q[..] {
&[name, "schala"] => name,
&[name, "maaru"] => name,
_ => panic!("Bad filename {}", sourcefile),
};

169
src/robo_lang/mod.rs Normal file
View File

@ -0,0 +1,169 @@
extern crate itertools;
use self::itertools::Itertools;
use language::{ProgrammingLanguage, EvaluationMachine, ParseError, TokenError, LLVMCodeString};
pub struct Robo {
}
impl Robo {
pub fn new() -> Robo {
Robo { }
}
}
pub struct RoboEvaluator {
pub trace_evaluation: bool,
}
#[derive(Debug)]
pub enum Token {
StrLiteral(String),
Backtick,
Newline,
LParen,
RParen,
LBracket,
RBracket,
LBrace,
RBrace,
Period,
Comma,
Colon,
Semicolon,
SingleQuote,
Identifier(String),
Operator(String),
NumLiteral(Number),
}
#[derive(Debug)]
pub enum Number {
IntegerRep(String),
FloatRep(String)
}
pub type AST = Vec<ASTNode>;
#[derive(Debug)]
pub enum ASTNode {
FunctionDefinition(String, Expression),
ImportStatement(String),
}
#[derive(Debug)]
pub enum Expression {
}
impl ProgrammingLanguage for Robo {
type Token = Token;
type AST = AST;
type Evaluator = RoboEvaluator;
fn name() -> String {
"Robo".to_string()
}
fn tokenize(input: &str) -> Result<Vec<Self::Token>, TokenError> {
use self::Token::*;
let mut tokens = Vec::new();
let mut iter = input.chars().peekable();
while let Some(c) = iter.next() {
if c == ';' {
while let Some(c) = iter.next() {
if c == '\n' {
break;
}
}
continue;
}
let cur_tok = match c {
c if char::is_whitespace(c) && c != '\n' => continue,
'\n' => Newline,
'(' => LParen,
')' => RParen,
'[' => LBracket,
']' => RBracket,
'{' => LBrace,
'}' => RBrace,
',' => Comma,
':' => Colon,
';' => Semicolon,
'.' => Period,
'`' => Backtick,
'\'' => SingleQuote,
'"' => {
let mut buffer = String::new();
loop {
match iter.next() {
Some(x) if x == '"' => break,
Some(x) => buffer.push(x),
None => return Err(TokenError::new("Unclosed quote")),
}
}
StrLiteral(buffer)
}
c if c.is_digit(10) => {
let mut integer = true;
let mut buffer = String::new();
buffer.push(c);
buffer.extend(iter.peeking_take_while(|x| x.is_digit(10)));
if let Some(&'.') = iter.peek() {
buffer.push(iter.next().unwrap());
integer = false;
}
buffer.extend(iter.peeking_take_while(|x| x.is_digit(10)));
let inner = if integer {
Number::IntegerRep(buffer)
} else {
Number::FloatRep(buffer)
};
NumLiteral(inner)
},
c if char::is_alphanumeric(c) => {
let mut buffer = String::new();
buffer.push(c);
buffer.extend(iter.peeking_take_while(|x| char::is_alphanumeric(*x)));
Identifier(buffer)
},
c => {
let mut buffer = String::new();
buffer.push(c);
buffer.extend(iter.peeking_take_while(|x| !char::is_whitespace(*x)));
Operator(buffer)
}
};
tokens.push(cur_tok);
}
Ok(tokens)
}
fn parse(_input: Vec<Self::Token>) -> Result<Self::AST, ParseError> {
Ok(vec!())
}
fn evaluate(_ast: Self::AST, _evaluator: &mut Self::Evaluator) -> Vec<String> {
vec!["Unimplemented".to_string()]
}
fn compile(_ast: Self::AST) -> LLVMCodeString {
unimplemented!()
}
}
impl EvaluationMachine for RoboEvaluator {
fn set_option(&mut self, option: &str, value: bool) -> bool {
if option == "trace_evaluation" {
self.trace_evaluation = value;
return true;
}
false
}
fn new() -> RoboEvaluator {
RoboEvaluator {
trace_evaluation: false,
}
}
}

View File

@ -1,54 +0,0 @@
use ::std::marker::PhantomData;
pub mod tokenizer;
pub mod parser;
pub mod eval;
pub mod compilation;
use language::{ProgrammingLanguage, EvaluationMachine, ParseError, TokenError, LLVMCodeString};
pub use self::eval::Evaluator as SchalaEvaluator;
pub struct Schala<'a> { marker: PhantomData<&'a ()> }
impl<'a> Schala<'a> {
pub fn new() -> Schala<'a> {
Schala { marker: PhantomData }
}
}
impl<'a> ProgrammingLanguage for Schala<'a> {
type Token = tokenizer::Token;
type AST = parser::AST;
type Evaluator = SchalaEvaluator<'a>;
fn name() -> String {
"Schala".to_string()
}
fn tokenize(input: &str) -> Result<Vec<Self::Token>, TokenError> {
tokenizer::tokenize(input)
}
fn parse(input: Vec<Self::Token>) -> Result<Self::AST, ParseError> {
parser::parse(&input, &[]).map_err(|x| ParseError { msg: x.msg })
}
fn evaluate(ast: Self::AST, evaluator: &mut Self::Evaluator) -> Vec<String> {
evaluator.run(ast)
}
fn compile(ast: Self::AST) -> LLVMCodeString {
compilation::compile_ast(ast)
}
}
impl<'a> EvaluationMachine for SchalaEvaluator<'a> {
fn set_option(&mut self, option: &str, value: bool) -> bool {
if option == "trace_evaluation" {
self.trace_evaluation = value;
return true;
}
false
}
fn new() -> SchalaEvaluator<'a> {
SchalaEvaluator::new(None)
}
}