Skip to content

Instantly share code, notes, and snippets.

@agmike
Last active August 29, 2015 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agmike/0ae5ffd666d2f76b7551 to your computer and use it in GitHub Desktop.
Save agmike/0ae5ffd666d2f76b7551 to your computer and use it in GitHub Desktop.
extern crate parser_combinators;
use parser_combinators::*;
#[derive(Debug)]
struct IncludeDecl { pub file: String }
#[derive(Debug)]
struct ClassDecl { pub name: String }
// Problems:
// returning closure: make_parser<I, O, F>() -> F
// where F: FnMut(State<I>) -> ParseResult<O, I>
// , I: Stream
// cloning closures
// Matches a token and consumes trailing space
macro_rules! token {
($e:expr) => ( ($e).skip(spaces()) )
}
// Matches an identifier ([_a-z][_a-z0-9]) and consumes trailing space
macro_rules! ident {
() => (
letter().or(char('_')).then(
// TODO: more efficient handling w/o allocation?
|c| { many(alpha_num()).map(move |s: String| { c.to_string() + &s }) }
).skip(spaces())
)
}
macro_rules! constant_string {
() => ( {
let simple_char = satisfy(|c| c != '"' && c != '\\');
let escape_quote = try(string("\\\"").map(|_| '\"'));
token!(between(char('"'), char('"'),
many(simple_char.or(escape_quote)).map(|s: String| s)
))
} )
}
// include_list -> include_declaration
// include_list -> include_list include_declaration
// include_declaration -> KEYWORD_INCLUDE include_file
// include_file -> CONSTANT_STRING
macro_rules! include_file {
() => ( constant_string!() )
}
macro_rules! kw_include {
() => ( token!(string("include")) )
}
macro_rules! include_decl {
() => (
kw_include!().with(
include_file!().map(|s| IncludeDecl { file: s })
)
)
}
// class_declaration_list -> class_declaration
// class_declaration_list -> class_declaration_list class_declaration
// class_declaration -> KEYWORD_CLASS identifier '{' '}' ';'
// class_declaration -> KEYWORD_CLASS identifier KEYWORD_ISCLASS class_list '{' '}' ';'
// class_declaration -> declaration_specifiers KEYWORD_CLASS identifier '{' '}' ';'
// class_declaration -> declaration_specifiers KEYWORD_CLASS identifier KEYWORD_ISCLASS class_list '{' '}' ';'
// class_declaration -> KEYWORD_CLASS identifier '{' declaration_list '}' ';'
// class_declaration -> KEYWORD_CLASS identifier KEYWORD_ISCLASS class_list '{' declaration_list '}' ';'
// class_declaration -> declaration_specifiers KEYWORD_CLASS identifier '{' declaration_list '}' ';'
// class_declaration -> declaration_specifiers KEYWORD_CLASS identifier KEYWORD_ISCLASS class_list '{' declaration_list '}' ';'
// class_list -> identifier
// class_list -> class_list ',' identifier
macro_rules! declaration_list {
() => ( value(Vec::<String>::new()) )
}
macro_rules! class_list {
() => ( sep_by(ident!(), token!(char(','))).map(|x: Vec<_>| x) )
}
macro_rules! class_decl {
() => ( {
token!(string("class")).with(ident!()).then(|class_name| {
optional(token!(string("isclass")).with(class_list!())).then(|base_classes| {
token!(char(';'))
// Parser::or( token!(char(';')).map(|_| None)
// , between( token!(char('{'))
// , token!(char('}'))
// , declaration_list!()
// ).skip(token!(char(';'))).map(Option::Some)
// )
})
})
} )
}
// program -> include_list class_declaration_list
// program -> class_declaration_list
macro_rules! include_list {
() => ( many(include_decl!()).map(|x: Vec<_>| x) )
}
macro_rules! class_decl_list {
() => ( many1(class_decl!()).map(|x: Vec<_>| x) )
}
macro_rules! program {
() => {
spaces().with(include_list!().and(class_decl_list!()))
}
}
pub fn parse() {
let src = r#"
include "gs.gs"
include "locomotive.gs"
class Test; {
public void DoIt() {
Interface.Exception("Hello, world!");
}
};
"#;
//let mut program = program!();
// Expanded version of the above line
let mut program =
spaces()
.with(many(
// keyword 'include'
(string("include")).skip(spaces()).with({
// string literal
let simple_char = satisfy(|c| c != '\"' && c != '\\');
let escape_quote = try (string("\\n").map( | _ | '\n'));
(between(char('\"'), char('\"'), many(simple_char.or(escape_quote)).map(|s: String| s))).skip(spaces())
}.map(|s| IncludeDecl { file: s, }))
).map(|x: Vec<_>| x)
.and(many1({
// keyword 'class'
(string("class")).skip(spaces())
// identifier
.with(letter().or(char('_')).then(|c| {
many(alpha_num()).map(move |s: String| { c.to_string() + &s })
}).skip(spaces()))
.then(|class_name| {
// keyword 'isclass'
optional((string("isclass")).skip(spaces())
// class_list
.with(sep_by(
// identifier
letter().or(char('_')).then(|c| {
many(alpha_num()).map(move |s: String| { c.to_string() + &s })
}).skip(spaces()),
char(',').skip(spaces())
)
.map(|x: Vec<_>| x))
).then(|base_classes| {
char(';').skip(spaces())
})
})
}).map(|x: Vec<_>| x)));
let result = program.parse(src);
match result {
Ok(((incls, classes), _)) => println!("Success: {:?} {:?}", incls, classes),
Err(e) => println!("{}", e)
}
}
// $ rustc /home/m1ke/src/schemegen/gamescript_syntax/src/lib.rs --crate-name gamescript_syntax --crate-type lib -g -C metadata=f30b929bc547d1a3 -C extra-filename=-f30b929bc547d1a3 --out-dir /home/m1ke/src/schemegen/schemegen/target/debug/deps --emit=dep-info,link -L dependency=/home/m1ke/src/schemegen/schemegen/target/debug/deps -L dependency=/home/m1ke/src/schemegen/schemegen/target/debug/deps --extern parser_combinators=/home/m1ke/src/schemegen/schemegen/target/debug/deps/libparser_combinators-11418352b9356529.rlib -Z time-passes
// time: 0.003 parsing
// time: 0.001 configuration 1
// time: 0.000 recursion limit
// time: 0.000 gated macro checking
// time: 0.000 crate injection
// time: 0.012 macro loading
// time: 0.000 plugin loading
// time: 0.000 plugin registration
// time: 0.005 expansion
// time: 0.000 complete gated feature checking 1
// time: 0.001 configuration 2
// time: 0.000 maybe building test harness
// time: 0.000 prelude injection
// time: 0.000 checking that all macro invocations are gone
// time: 0.000 complete gated feature checking 2
// time: 0.000 assigning node ids and indexing ast
// time: 0.000 external crate/lib resolution
// time: 0.000 language item collection
// time: 0.004 resolution
// time: 0.000 lifetime resolution
// time: 0.000 looking for entry point
// time: 0.000 looking for plugin registrar
// time: 0.000 region resolution
// time: 0.000 loop checking
// time: 0.000 static item recursion checking
// time: 0.001 type collecting
// time: 0.000 variance inference
// time: 0.006 coherence checking
// time: 179.359 type checking
// time: 0.236 const checking
// time: 0.057 privacy checking
// time: 0.000 stability index
// time: 0.017 intrinsic checking
// time: 0.000 effect checking
// time: 0.057 match checking
// time: 0.001 liveness checking
// time: 0.270 borrow checking
// time: 0.067 rvalue checking
// time: 0.000 reachability checking
// time: 0.000 death checking
// time: 0.065 stability checking
// time: 0.000 unused lib feature checking
// time: 0.384 lint checking
// time: 0.000 resolving dependency formats
// time: 516.564 translation
// time: 0.090 llvm function passes
// time: 0.031 llvm module passes
// time: 1.104 codegen passes
// time: 0.001 codegen passes
// time: 2.155 LLVM passes
// time: 0.236 linking
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment