Add functions
This commit is contained in:
parent
cf0f4fc0b9
commit
86c2b13d1a
@ -1,2 +1 @@
|
|||||||
let otus = "dotus";
|
print();
|
||||||
let botus = otus;
|
|
@ -62,6 +62,7 @@ impl Compiler {
|
|||||||
self.list.push(Command::EndScope);
|
self.list.push(Command::EndScope);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
Expression::FunctionCall(..) => Err(CompilerError::Fatal),
|
||||||
Expression::ValueRef(_, val) => match val {
|
Expression::ValueRef(_, val) => match val {
|
||||||
Pattern::IdentPattern(pos, ident) => {
|
Pattern::IdentPattern(pos, ident) => {
|
||||||
if let Some(var) = self.root_scope.get(ident.clone()) {
|
if let Some(var) = self.root_scope.get(ident.clone()) {
|
||||||
|
@ -17,6 +17,7 @@ const ALLOWED_IDENT_BEGIN_CHARS: [char; 26] = [
|
|||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
text: Vec<char>,
|
text: Vec<char>,
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
|
inconfidence: usize,
|
||||||
line_number: usize,
|
line_number: usize,
|
||||||
character_number: usize,
|
character_number: usize,
|
||||||
}
|
}
|
||||||
@ -26,6 +27,7 @@ impl Parser {
|
|||||||
Parser {
|
Parser {
|
||||||
text: text.chars().collect(),
|
text: text.chars().collect(),
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
|
inconfidence: 0,
|
||||||
line_number: 0,
|
line_number: 0,
|
||||||
character_number: 0,
|
character_number: 0,
|
||||||
}
|
}
|
||||||
@ -37,7 +39,7 @@ impl Parser {
|
|||||||
let mut error = None;
|
let mut error = None;
|
||||||
|
|
||||||
while {
|
while {
|
||||||
self.skip_whitespace();
|
self.skip_whitespace_confident(true);
|
||||||
if self.remaining() > 0 {
|
if self.remaining() > 0 {
|
||||||
match Statement::parse(&mut self) {
|
match Statement::parse(&mut self) {
|
||||||
Ok(exp) => {
|
Ok(exp) => {
|
||||||
@ -76,12 +78,20 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect<T: Into<String>>(&mut self, expected: T) -> Expect {
|
pub fn expect<T: Into<String>>(&mut self, expectable: Expectable<T>) -> Expect {
|
||||||
|
match expectable {
|
||||||
|
Expectable::Static(val) => self.expect_static(val),
|
||||||
|
Ident => self.expect_ident(),
|
||||||
|
StringLit => self.expect_string_lit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_static<T: Into<String>>(&mut self, expected: T) -> Expect {
|
||||||
let expected = expected.into();
|
let expected = expected.into();
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
let mut result = Some(expected.clone());
|
let mut result = Some(expected.clone());
|
||||||
for (idx, c) in expected.chars().enumerate() {
|
for (idx, c) in expected.chars().enumerate() {
|
||||||
if let Some(peek) = self.peek(idx) {
|
if let Some(peek) = self.peek(idx + self.inconfidence) {
|
||||||
if peek != c {
|
if peek != c {
|
||||||
result = None;
|
result = None;
|
||||||
}
|
}
|
||||||
@ -90,9 +100,9 @@ impl Parser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.inconfidence += expected.len();
|
||||||
Expect {
|
Expect {
|
||||||
text: result,
|
text: result,
|
||||||
len: expected.len(),
|
|
||||||
parser: self,
|
parser: self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,14 +110,13 @@ impl Parser {
|
|||||||
pub fn expect_ident(&mut self) -> Expect {
|
pub fn expect_ident(&mut self) -> Expect {
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
let mut ident: Option<String> = None;
|
let mut ident: Option<String> = None;
|
||||||
let mut len = 0;
|
|
||||||
while {
|
while {
|
||||||
if let Some(peek) = self.peek(len) {
|
if let Some(peek) = self.peek(self.inconfidence) {
|
||||||
let lowercase = &peek.to_ascii_lowercase();
|
let lowercase = &peek.to_ascii_lowercase();
|
||||||
if let Some(id) = &mut ident {
|
if let Some(id) = &mut ident {
|
||||||
if ALLOWED_IDENT_CHARS.contains(lowercase) {
|
if ALLOWED_IDENT_CHARS.contains(lowercase) {
|
||||||
id.push(peek);
|
id.push(peek);
|
||||||
len += 1;
|
self.inconfidence += 1;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -115,7 +124,7 @@ impl Parser {
|
|||||||
} else {
|
} else {
|
||||||
if ALLOWED_IDENT_BEGIN_CHARS.contains(lowercase) {
|
if ALLOWED_IDENT_BEGIN_CHARS.contains(lowercase) {
|
||||||
ident = Some(peek.to_string());
|
ident = Some(peek.to_string());
|
||||||
len += 1;
|
self.inconfidence += 1;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -127,7 +136,6 @@ impl Parser {
|
|||||||
} {}
|
} {}
|
||||||
Expect {
|
Expect {
|
||||||
text: ident,
|
text: ident,
|
||||||
len: len,
|
|
||||||
parser: self,
|
parser: self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,22 +143,21 @@ impl Parser {
|
|||||||
pub fn expect_string_lit(&mut self) -> Expect {
|
pub fn expect_string_lit(&mut self) -> Expect {
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
let mut content: Option<String> = None;
|
let mut content: Option<String> = None;
|
||||||
let mut len = 0;
|
|
||||||
while {
|
while {
|
||||||
if let Some(peek) = self.peek(len) {
|
if let Some(peek) = self.peek(self.inconfidence) {
|
||||||
if let Some(cont) = &mut content {
|
if let Some(cont) = &mut content {
|
||||||
if peek == '"' {
|
if peek == '"' {
|
||||||
len += 1;
|
self.inconfidence += 1;
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
cont.push(peek);
|
cont.push(peek);
|
||||||
len += 1;
|
self.inconfidence += 1;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if peek == '"' {
|
if peek == '"' {
|
||||||
content = Some(String::new());
|
content = Some(String::new());
|
||||||
len += 1;
|
self.inconfidence += 1;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -162,12 +169,11 @@ impl Parser {
|
|||||||
} {}
|
} {}
|
||||||
Expect {
|
Expect {
|
||||||
text: content,
|
text: content,
|
||||||
len: len,
|
|
||||||
parser: self,
|
parser: self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_cursor(&mut self) {
|
pub fn advance_cursor(&mut self) {
|
||||||
let curr = self.peek(0).unwrap();
|
let curr = self.peek(0).unwrap();
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
self.character_number += 1;
|
self.character_number += 1;
|
||||||
@ -177,9 +183,9 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_cursor_multiple(&mut self, amount: usize) {
|
pub fn advance_cursor_multiple(&mut self, amount: usize) {
|
||||||
for _ in 0..amount {
|
for _ in 0..amount {
|
||||||
self.move_cursor();
|
self.advance_cursor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,36 +193,102 @@ impl Parser {
|
|||||||
Position(self.line_number, self.character_number)
|
Position(self.line_number, self.character_number)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_whitespace(&mut self) {
|
fn skip_whitespace_confident(&mut self, confident: bool) {
|
||||||
let mut next = ' ';
|
let mut next = ' ';
|
||||||
while self.remaining() > 0 && {
|
while self.remaining() > 0 && {
|
||||||
next = self.peek(0).unwrap();
|
next = self.peek(self.inconfidence).unwrap();
|
||||||
next == ' ' || next == '\n' || next == '\r' || next == '\t'
|
next == ' ' || next == '\n' || next == '\r' || next == '\t'
|
||||||
} {
|
} {
|
||||||
self.move_cursor();
|
if confident {
|
||||||
|
self.advance_cursor();
|
||||||
|
} else {
|
||||||
|
self.inconfidence += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn skip_whitespace(&mut self) {
|
||||||
|
self.skip_whitespace_confident(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Expectable<T: Into<String>> {
|
||||||
|
Static(T),
|
||||||
|
Ident,
|
||||||
|
StringLit,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Expect<'a> {
|
pub struct Expect<'a> {
|
||||||
text: Option<String>,
|
text: Option<String>,
|
||||||
len: usize,
|
|
||||||
parser: &'a mut Parser,
|
parser: &'a mut Parser,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expect<'_> {
|
impl<'a> Expect<'a> {
|
||||||
pub fn get(self) -> Option<String> {
|
pub fn get_inconfident(self) -> Option<String> {
|
||||||
if self.text.is_some() {
|
|
||||||
self.parser.move_cursor_multiple(self.len);
|
|
||||||
}
|
|
||||||
self.text
|
self.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get(self) -> Option<String> {
|
||||||
|
if self.text.is_some() {
|
||||||
|
self.parser
|
||||||
|
.advance_cursor_multiple(self.parser.inconfidence);
|
||||||
|
}
|
||||||
|
self.parser.inconfidence = 0;
|
||||||
|
self.text
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_or(self, error: SyntaxError) -> Result<String, SyntaxError> {
|
pub fn get_or(self, error: SyntaxError) -> Result<String, SyntaxError> {
|
||||||
match self.get() {
|
match self.get() {
|
||||||
Some(text) => Ok(text),
|
Some(text) => Ok(text),
|
||||||
None => Err(error),
|
None => Err(error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn and<'b, T: Into<String>>(self, other: Expectable<T>) -> Expects<'a> {
|
||||||
|
let texts = if let Some(text) = self.text {
|
||||||
|
Some(vec![text])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Expects::and(
|
||||||
|
Expects {
|
||||||
|
texts: texts,
|
||||||
|
parser: self.parser,
|
||||||
|
},
|
||||||
|
other,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_expect<T: Into<String>>(&mut self, expectable: Expectable<T>) -> Expect {
|
||||||
|
self.parser.expect(expectable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Expects<'a> {
|
||||||
|
texts: Option<Vec<String>>,
|
||||||
|
parser: &'a mut Parser,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Expects<'a> {
|
||||||
|
pub fn and<'b, T: Into<String>>(mut self, expect: Expectable<T>) -> Expects<'a> {
|
||||||
|
let other = self.parser.expect(expect);
|
||||||
|
if let Some(texts) = &mut self.texts {
|
||||||
|
if let Some(text) = other.get_inconfident() {
|
||||||
|
texts.push(text);
|
||||||
|
} else {
|
||||||
|
self.texts = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self) -> Option<Vec<String>> {
|
||||||
|
if self.texts.is_some() {
|
||||||
|
self.parser
|
||||||
|
.advance_cursor_multiple(self.parser.inconfidence);
|
||||||
|
}
|
||||||
|
self.parser.inconfidence = 0;
|
||||||
|
self.texts
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{Parser, Position, SyntaxError};
|
use super::{Expectable, Parser, Position, SyntaxError};
|
||||||
|
|
||||||
type Ident = String;
|
type Ident = String;
|
||||||
|
|
||||||
@ -15,17 +15,17 @@ impl Statement {
|
|||||||
pub fn parse(parser: &mut Parser) -> Result<Statement, SyntaxError> {
|
pub fn parse(parser: &mut Parser) -> Result<Statement, SyntaxError> {
|
||||||
let pos = parser.pos();
|
let pos = parser.pos();
|
||||||
|
|
||||||
if let Some(_) = parser.expect("let").get() {
|
if let Some(_) = parser.expect_static("let").get() {
|
||||||
let ident = parser
|
let ident = parser
|
||||||
.expect_ident()
|
.expect_ident()
|
||||||
.get_or(SyntaxError::ExpectedIdent(pos))?;
|
.get_or(SyntaxError::ExpectedIdent(pos))?;
|
||||||
parser
|
parser
|
||||||
.expect("=")
|
.expect_static("=")
|
||||||
.get_or(SyntaxError::ExpectedToken(pos, '='))?;
|
.get_or(SyntaxError::ExpectedToken(pos, '='))?;
|
||||||
match Expression::parse(parser) {
|
match Expression::parse(parser) {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
parser
|
parser
|
||||||
.expect(";")
|
.expect_static(";")
|
||||||
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
||||||
Ok(Statement::LetStatement(pos, ident, Box::new(expr)))
|
Ok(Statement::LetStatement(pos, ident, Box::new(expr)))
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ impl Statement {
|
|||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
let statement = Statement::ExprStatement(pos, expr);
|
let statement = Statement::ExprStatement(pos, expr);
|
||||||
parser
|
parser
|
||||||
.expect(";")
|
.expect_static(";")
|
||||||
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
||||||
Ok(statement)
|
Ok(statement)
|
||||||
}
|
}
|
||||||
@ -49,6 +49,7 @@ impl Statement {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
BlockExpr(Position, Vec<Statement>),
|
BlockExpr(Position, Vec<Statement>),
|
||||||
|
FunctionCall(Position, Ident, Vec<Expression>),
|
||||||
ValueRef(Position, Pattern),
|
ValueRef(Position, Pattern),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +57,7 @@ impl Expression {
|
|||||||
pub fn parse(parser: &mut Parser) -> Result<Expression, SyntaxError> {
|
pub fn parse(parser: &mut Parser) -> Result<Expression, SyntaxError> {
|
||||||
let begin_pos = parser.pos();
|
let begin_pos = parser.pos();
|
||||||
|
|
||||||
let expect = parser.expect("{");
|
if let Some(_) = parser.expect_static("{").get() {
|
||||||
if let Some(_) = expect.get() {
|
|
||||||
let mut statement_list = Vec::new();
|
let mut statement_list = Vec::new();
|
||||||
while {
|
while {
|
||||||
match Statement::parse(parser) {
|
match Statement::parse(parser) {
|
||||||
@ -68,11 +68,38 @@ impl Expression {
|
|||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
}
|
}
|
||||||
} {}
|
} {}
|
||||||
if let Some(_) = parser.expect("}").get() {
|
if let Some(_) = parser.expect_static("}").get() {
|
||||||
Ok(Expression::BlockExpr(begin_pos, statement_list))
|
Ok(Expression::BlockExpr(begin_pos, statement_list))
|
||||||
} else {
|
} else {
|
||||||
Err(SyntaxError::ExpectedToken(parser.pos(), '}'))
|
Err(SyntaxError::ExpectedToken(parser.pos(), '}'))
|
||||||
}
|
}
|
||||||
|
} else if let Some(texts) = parser.expect_ident().and(Expectable::Static("(")).get() {
|
||||||
|
let name = texts.get(0).unwrap();
|
||||||
|
let mut arg_list = Vec::new();
|
||||||
|
while {
|
||||||
|
match Expression::parse(parser) {
|
||||||
|
Ok(exp) => {
|
||||||
|
arg_list.push(exp);
|
||||||
|
if let Some(_) = parser.expect_static(",").get() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
if arg_list.is_empty() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
let pos = parser.pos();
|
||||||
|
parser
|
||||||
|
.expect_static(")")
|
||||||
|
.get_or(SyntaxError::ExpectedToken(pos, ')'))?;
|
||||||
|
Ok(Expression::FunctionCall(pos, name.clone(), arg_list))
|
||||||
} else if let Ok(pattern) = Pattern::parse(parser) {
|
} else if let Ok(pattern) = Pattern::parse(parser) {
|
||||||
Ok(Expression::ValueRef(begin_pos, pattern))
|
Ok(Expression::ValueRef(begin_pos, pattern))
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user