Compare commits
5 Commits
086fcf6dd9
...
5f508eee12
Author | SHA1 | Date | |
---|---|---|---|
|
5f508eee12 | ||
|
f223e2401e | ||
|
ba8f867bd9 | ||
|
8852ca6fe2 | ||
df49e28f78 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
target/
|
||||
SDL2*.dll
|
||||
|
||||
|
@ -11,8 +11,7 @@ element_fields -> (_ element_field (__linebreak__ element_field):*):? __linebrea
|
||||
|
||||
element_field ->
|
||||
| element
|
||||
| Id
|
||||
| Class
|
||||
| specifier_chain
|
||||
| element_property
|
||||
| value
|
||||
|
||||
@ -20,22 +19,20 @@ element_property -> Name _ ("=" | ":") _ value
|
||||
|
||||
single_line_fields ->
|
||||
(first_single_line_field
|
||||
(__singleline__ single_line_field):*):? _singleline_
|
||||
(__sl__ single_line_field):*):? _sl_
|
||||
|
||||
first_single_line_field ->
|
||||
| Id
|
||||
| Class
|
||||
| __singleline__ single_line_element_property
|
||||
| __singleline__ single_line_value
|
||||
| specifier_chain
|
||||
| __sl__ single_line_element_property
|
||||
| __sl__ single_line_value
|
||||
|
||||
single_line_field ->
|
||||
| Id
|
||||
| Class
|
||||
| specifier_chain
|
||||
| single_line_element_property
|
||||
| single_line_value
|
||||
|
||||
single_line_element_property ->
|
||||
Name _singleline_ ("=" | ":") _singleline_ value
|
||||
Name _sl_ ("=" | ":") _sl_ value
|
||||
|
||||
single_line_value ->
|
||||
| array
|
||||
@ -45,6 +42,12 @@ single_line_value ->
|
||||
| bool
|
||||
| Null
|
||||
|
||||
specifier_chain -> specifier:+
|
||||
|
||||
specifier ->
|
||||
| Id
|
||||
| Class
|
||||
|
||||
value ->
|
||||
| object
|
||||
| array
|
||||
@ -56,7 +59,8 @@ value ->
|
||||
|
||||
object -> "{" object_properties "}"
|
||||
|
||||
object_properties -> (_ object_property (_ "," _ object_property):* _ ",":?):? _
|
||||
object_properties ->
|
||||
(_ object_property (_ "," _ object_property):* _ ",":?):? _
|
||||
|
||||
object_property -> (Name | String) _ ("=" | ":") _ value
|
||||
|
||||
@ -66,28 +70,27 @@ array_values -> (_ value (_ "," _ value):* _ ",":?):? _
|
||||
|
||||
bool -> True | False
|
||||
|
||||
__singleline__ -> mandatory_same_line_whitespace
|
||||
_singleline_ -> optional_same_line_whitespace
|
||||
__linebreak__ -> mandatory_linebreak
|
||||
__ -> mandatory_whitespace
|
||||
__sl__ -> mandatory_single_line_whitespace
|
||||
_sl_ -> optional_single_line_whitespace
|
||||
__ml__ -> mandatory_whitespace
|
||||
_ -> optional_whitespace
|
||||
|
||||
mandatory_same_line_whitespace -> single_line_whitespace:+
|
||||
optional_same_line_whitespace -> single_line_whitespace:*
|
||||
|
||||
mandatory_linebreak ->
|
||||
single_line_whitespace:*
|
||||
line_breaker
|
||||
whitespace_and_line_break:*
|
||||
|
||||
single_line_whitespace -> SingleLineWhitespace | MultiLineComment
|
||||
|
||||
line_breaker -> MultiLineComment | MultiLineWhitespace | ";"
|
||||
|
||||
whitespace_and_line_break -> singular_whitespace | ";"
|
||||
|
||||
optional_whitespace -> singular_whitespace:*
|
||||
mandatory_single_line_whitespace -> single_line_whitespace:+
|
||||
optional_single_line_whitespace -> single_line_whitespace:*
|
||||
|
||||
single_line_whitespace -> SingleLineWhitespace | MultiLineComment
|
||||
|
||||
optional_whitespace -> singular_whitespace:*
|
||||
mandatory_whitespace -> singular_whitespace:+
|
||||
|
||||
singular_whitespace ->
|
||||
|
@ -1,17 +1,17 @@
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ErrorType {
|
||||
UnexpectedToken(char),
|
||||
InvalidConstructor,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Error {
|
||||
error: ErrorType,
|
||||
line: isize,
|
||||
col: isize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Token {
|
||||
Name(String),
|
||||
Id(String),
|
||||
@ -30,10 +30,10 @@ pub enum Token {
|
||||
RBrace(String),
|
||||
LBracket(String),
|
||||
RBracket(String),
|
||||
Equal(String),
|
||||
Colon(String),
|
||||
SemiColon(String),
|
||||
Comma(String),
|
||||
Equal(String), // not implemented
|
||||
Colon(String), // not implemented
|
||||
SemiColon(String), // not implemented
|
||||
Comma(String), // not implemented
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
@ -27,6 +27,13 @@ pub struct Parser {
|
||||
|
||||
type ParserError = String;
|
||||
|
||||
enum ElementField {
|
||||
Id(String),
|
||||
Class(String),
|
||||
Property(Box<Node>),
|
||||
Value(Node),
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(tokens: Vec<Token>) -> Self {
|
||||
Self { tokens, index: 0 }
|
||||
@ -41,23 +48,63 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_element(&mut self) -> Result<Node, ParserError> {
|
||||
let name = match self.current() {
|
||||
Some(Token::Name(value)) => value.clone(),
|
||||
_ => panic!("checked by previous predicate"),
|
||||
};
|
||||
self.step();
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse_singe_line_fields(&mut self) -> Result<Vec<ElementField>, ParserError> {
|
||||
let mut fields = Vec::<ElementField>::new();
|
||||
match self.current() {
|
||||
Some(Token::Id(value)) => {
|
||||
fields.push(ElementField::Id(value.clone()));
|
||||
self.step();
|
||||
todo!()
|
||||
}
|
||||
Some(Token::Class(value)) => {
|
||||
fields.push(ElementField::Class(value.clone()));
|
||||
self.step();
|
||||
todo!()
|
||||
}
|
||||
Some(_) => todo!(),
|
||||
_ => Ok(fields),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_value(&mut self) -> Result<Node, ParserError> {
|
||||
match self.current() {
|
||||
Some(Token::LBrace(_)) => self.parse_object(),
|
||||
Some(Token::LBracket(_)) => self.parse_object(),
|
||||
Some(Token::Int(value)) => Ok(Node::Int(
|
||||
value.parse().map_err(|_| "malformed int".to_string())?,
|
||||
)),
|
||||
Some(Token::Float(value)) => Ok(Node::Int(
|
||||
value.parse().map_err(|_| "malformed float".to_string())?,
|
||||
)),
|
||||
Some(Token::String(value)) => Ok(Node::String(value[1..value.len() - 1].to_string())),
|
||||
Some(Token::False(_)) => Ok(Node::Bool(false)),
|
||||
Some(Token::True(_)) => Ok(Node::Bool(false)),
|
||||
Some(Token::Null(_)) => Ok(Node::Null),
|
||||
Some(Token::Int(value)) => {
|
||||
let value = value.parse().map_err(|_| "malformed int".to_string())?;
|
||||
self.step();
|
||||
Ok(Node::Int(value))
|
||||
}
|
||||
Some(Token::Float(value)) => {
|
||||
let value = value.parse().map_err(|_| "malformed float".to_string())?;
|
||||
self.step();
|
||||
Ok(Node::Float(value))
|
||||
}
|
||||
Some(Token::String(value)) => {
|
||||
let value = value[1..value.len() - 1].to_string();
|
||||
self.step();
|
||||
Ok(Node::String(value))
|
||||
}
|
||||
Some(Token::False(_)) => {
|
||||
self.step();
|
||||
Ok(Node::Bool(false))
|
||||
}
|
||||
Some(Token::True(_)) => {
|
||||
self.step();
|
||||
Ok(Node::Bool(false))
|
||||
}
|
||||
Some(Token::Null(_)) => {
|
||||
self.step();
|
||||
Ok(Node::Null)
|
||||
}
|
||||
Some(_) => Err("unexpected token, expected value".to_owned()),
|
||||
None => Err("expected value".to_owned()),
|
||||
}
|
||||
@ -65,6 +112,8 @@ impl Parser {
|
||||
|
||||
fn parse_object(&mut self) -> Result<Node, ParserError> {
|
||||
self.step();
|
||||
// object_properties -> (_ (...)):? _ <=> object_properties -> _ | _ (...) _
|
||||
self.parse_optional_whitespace()?;
|
||||
let mut values = HashMap::<String, Box<Node>>::new();
|
||||
match self.current() {
|
||||
Some(Token::RBrace(_)) => {
|
||||
@ -72,27 +121,32 @@ impl Parser {
|
||||
Ok(Node::Object(values))
|
||||
}
|
||||
Some(t @ (Token::Name(_) | Token::String(_))) => {
|
||||
// let key = match t {
|
||||
// Token::Name(v) => v,
|
||||
// Token::String(v) => &v[1..v.len() - 1].to_string(),
|
||||
// _ => panic!("checked by previous predicate"),
|
||||
// };
|
||||
// self.step();
|
||||
// match self.current() {
|
||||
// Some(Token::Equal(_) | Token::Colon(_)) => {}
|
||||
// _ => return Err("expected ':' or '='".to_string()),
|
||||
// }
|
||||
// self.step();
|
||||
// values[key] = Box::new(self.parse_value()?);
|
||||
// self.parse_object_tail(values)
|
||||
todo!()
|
||||
let key = match t {
|
||||
Token::Name(v) => v.clone(),
|
||||
Token::String(v) => v[1..v.len() - 1].to_string(),
|
||||
_ => panic!("checked by previous predicate"),
|
||||
};
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
match self.current() {
|
||||
Some(Token::Equal(_) | Token::Colon(_)) => {}
|
||||
_ => return Err("expected ':' or '='".to_string()),
|
||||
}
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
values.insert(key, Box::new(self.parse_value()?));
|
||||
self.parse_object_tail(values)
|
||||
}
|
||||
_ => Err("expected Name, String or '}'".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_object_tail(&mut self, values: HashMap<String, Box<Node>>) -> Result<Node, String> {
|
||||
fn parse_object_tail(
|
||||
&mut self,
|
||||
mut values: HashMap<String, Box<Node>>,
|
||||
) -> Result<Node, String> {
|
||||
loop {
|
||||
self.parse_optional_whitespace()?;
|
||||
match self.current() {
|
||||
Some(Token::RBrace(_)) => {
|
||||
self.step();
|
||||
@ -100,25 +154,28 @@ impl Parser {
|
||||
}
|
||||
Some(Token::Comma(_)) => {
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
match self.current() {
|
||||
Some(Token::RBrace(_)) => {
|
||||
self.step();
|
||||
break Ok(Node::Object(values));
|
||||
}
|
||||
Some(t @ (Token::Name(_) | Token::String(_))) => {
|
||||
// let key = match t {
|
||||
// Token::Name(v) => v,
|
||||
// Token::String(v) => &v[1..v.len() - 1].to_string(),
|
||||
// _ => panic!("unterminated object, checked by previous predicate"),
|
||||
// };
|
||||
// self.step();
|
||||
// match self.current() {
|
||||
// Some(Token::Equal(_) | Token::Colon(_)) => {}
|
||||
// _ => return Err("expected ':' or '='".to_string()),
|
||||
// }
|
||||
// self.step();
|
||||
// values[key] = Box::new(self.parse_value()?);
|
||||
todo!()
|
||||
let key = match t {
|
||||
Token::Name(v) => v.clone(),
|
||||
Token::String(v) => v[1..v.len() - 1].to_string(),
|
||||
_ => panic!("unterminated object, checked by previous predicate"),
|
||||
};
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
match self.current() {
|
||||
Some(Token::Equal(_) | Token::Colon(_)) => {}
|
||||
_ => return Err("expected ':' or '='".to_string()),
|
||||
}
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
values.insert(key, Box::new(self.parse_value()?));
|
||||
self.parse_optional_whitespace()?;
|
||||
}
|
||||
_ => {
|
||||
break Err(
|
||||
@ -134,6 +191,7 @@ impl Parser {
|
||||
|
||||
fn parse_array(&mut self) -> Result<Node, ParserError> {
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
let mut values = Vec::<Node>::new();
|
||||
match self.current() {
|
||||
Some(Token::RBracket(_)) => {
|
||||
@ -142,12 +200,112 @@ impl Parser {
|
||||
}
|
||||
Some(_) => {
|
||||
values.push(self.parse_value()?);
|
||||
todo!()
|
||||
loop {
|
||||
match self.current() {
|
||||
Some(Token::RBracket(_)) => {
|
||||
self.step();
|
||||
break Ok(Node::Array(values));
|
||||
}
|
||||
Some(Token::Comma(_)) => {
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
match self.current() {
|
||||
Some(Token::RBracket(_)) => {
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
break Ok(Node::Array(values));
|
||||
}
|
||||
_ => {
|
||||
self.step();
|
||||
self.parse_optional_whitespace()?;
|
||||
values.push(self.parse_value()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => break Err("unterminated array, expected Value or ']'".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err("unterminated array, expected Value or ']'".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_mandatory_linebreak(&mut self) -> Result<(), ParserError> {
|
||||
self.parse_single_line_optional_whitespace()?;
|
||||
match self.current() {
|
||||
Some(Token::MlWhitespace(_) | Token::MlComment(_) | Token::SemiColon(_)) => {
|
||||
self.step();
|
||||
loop {
|
||||
match self.current() {
|
||||
Some(
|
||||
Token::MlWhitespace(_)
|
||||
| Token::SlWhitespace(_)
|
||||
| Token::MlComment(_)
|
||||
| Token::SlComment(_)
|
||||
| Token::SemiColon(_),
|
||||
) => {
|
||||
self.step();
|
||||
}
|
||||
_ => break Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err("expected linebreak".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_single_line_mandatory_whitespace(&mut self) -> Result<(), ParserError> {
|
||||
match self.current() {
|
||||
Some(Token::SlWhitespace(_) | Token::SlComment(_)) => {
|
||||
self.step();
|
||||
self.parse_single_line_optional_whitespace()
|
||||
}
|
||||
_ => Err("expected whitespace".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_single_line_optional_whitespace(&mut self) -> Result<(), ParserError> {
|
||||
loop {
|
||||
match self.current() {
|
||||
Some(Token::SlWhitespace(_) | Token::SlComment(_)) => {
|
||||
self.step();
|
||||
}
|
||||
_ => break Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_mandatory_whitespace(&mut self) -> Result<(), ParserError> {
|
||||
match self.current() {
|
||||
Some(
|
||||
Token::MlWhitespace(_)
|
||||
| Token::SlWhitespace(_)
|
||||
| Token::MlComment(_)
|
||||
| Token::SlComment(_),
|
||||
) => {
|
||||
self.step();
|
||||
self.parse_optional_whitespace()
|
||||
}
|
||||
_ => Err("expected whitespace".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_optional_whitespace(&mut self) -> Result<(), ParserError> {
|
||||
loop {
|
||||
match self.current() {
|
||||
Some(
|
||||
Token::MlWhitespace(_)
|
||||
| Token::SlWhitespace(_)
|
||||
| Token::MlComment(_)
|
||||
| Token::SlComment(_),
|
||||
) => {
|
||||
self.step();
|
||||
}
|
||||
_ => break Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn step(&mut self) {
|
||||
self.index += 1
|
||||
}
|
||||
|
36
src/main.rs
36
src/main.rs
@ -1,9 +1,28 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use sdl2::{event::Event, keyboard::Keycode, pixels::Color};
|
||||
use sdl2::{
|
||||
event::Event, keyboard::Keycode, pixels::Color, rect::Rect, render::Canvas, video::Window,
|
||||
};
|
||||
|
||||
mod bong;
|
||||
|
||||
enum Element {
|
||||
Div(Vec<Element>),
|
||||
Rectangle(Color),
|
||||
}
|
||||
|
||||
impl Element {
|
||||
fn render(&self, canvas: &mut Canvas<Window>, x: i32, y: i32) {
|
||||
match self {
|
||||
Element::Div(_) => todo!(),
|
||||
Element::Rectangle(color) => {
|
||||
canvas.set_draw_color(*color);
|
||||
let _ = canvas.fill_rect(Rect::new(x, y, 50, 50));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
let video_subsystem = sdl_context.video().unwrap();
|
||||
@ -20,10 +39,8 @@ fn main() {
|
||||
canvas.clear();
|
||||
canvas.present();
|
||||
let mut event_pump = sdl_context.event_pump().unwrap();
|
||||
let mut i = 0;
|
||||
'running: loop {
|
||||
i = (i + 1) % 255;
|
||||
canvas.set_draw_color(Color::RGB(i, 64, 255 - i));
|
||||
'game_loop: loop {
|
||||
canvas.set_draw_color(Color::RGB(170, 200, 255));
|
||||
canvas.clear();
|
||||
for event in event_pump.poll_iter() {
|
||||
match event {
|
||||
@ -31,11 +48,18 @@ fn main() {
|
||||
| Event::KeyDown {
|
||||
keycode: Some(Keycode::Escape),
|
||||
..
|
||||
} => break 'running,
|
||||
} => break 'game_loop,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// The rest of the game loop goes here...
|
||||
let dom = Element::Div(vec![
|
||||
Element::Rectangle(Color::RGB(1, 238, 34)),
|
||||
Element::Rectangle(Color::RGB(123, 123, 123)),
|
||||
]);
|
||||
|
||||
canvas.set_draw_color(Color::RGB(255, 0, 0));
|
||||
let _ = canvas.fill_rect(Rect::new(0, 0, 50, 50));
|
||||
|
||||
canvas.present();
|
||||
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
||||
|
Loading…
Reference in New Issue
Block a user