diff options
author | JSDurand <mmemmew@gmail.com> | 2023-07-08 12:30:21 +0800 |
---|---|---|
committer | JSDurand <mmemmew@gmail.com> | 2023-07-08 12:31:13 +0800 |
commit | 9a317e56f8a6126583f7d0c431bf878d9b1fe7b1 (patch) | |
tree | 7bb6004196b38446a5ab0cb3a0ab642d35f113e9 /src/old binding.txt | |
parent | 691f969eb104fa3d4c2a1667693fd0382eb9d6b5 (diff) |
Finished the Emacs binding.
Now the binding part is finished.
What remains is a bug encountered when planting a fragment to the
forest which intersects a packed node, which would lead to invalid
forests. This will also cause problem when planting a packed
fragment, but until now my testing grammars do not produce packed
fragments, so this problem is not encountered yet.
I am still figuring out efficient ways to solve this problem.
Diffstat (limited to 'src/old binding.txt')
-rw-r--r-- | src/old binding.txt | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/src/old binding.txt b/src/old binding.txt new file mode 100644 index 0000000..0311f49 --- /dev/null +++ b/src/old binding.txt @@ -0,0 +1,218 @@ +//! This file provides the Emacs binding for the core. + +#![allow(unused_imports)] + +extern crate repcore; + +use repcore::{ + derive::stdag::{PFRecorder, STDAGParser}, + grammar::{Grammar, GrammarInfo}, + semiring::{IdentityRecorder, Nat, PFS}, + tokenizer::to_tokenizer, + valuation::{Count, ParseForest}, +}; + +use repcore::parser::Parser as PParser; +use repcore::parser::ParserReportConfig as PParserConfig; + +// TODO: Write Emacs binding + +// Let's design the API for Emacs to use. +// +// Emacs offers the grammar file or grammar string, and then we +// generate a parser. +// +// Thereafter when we want to parse some input, Emacs gives the input +// file name or the input file string to this package, and then the +// package gives back the parse result. +// +// Besides, we need a data type to deal with errors. +// +// Handling a string is not a problem for us, but to return a parser +// to Emacs, and to return the parse result, are kind of troublesome. +// +// To achieve this, we need data types for a parser and for the parse +// result. Since a parser is just an implementation detail and should +// not be of concern to the user, we mught just represent a parser as +// just a custom user-ptr in Emacs. +// +// As to the parse result, we return a set of tuples: +// +// (label, i, k, j), +// +// where LABEL is represented as a tuple +// +// (INDEX, STRING), +// +// where index is the index of the rule and the string is the name of +// the non-terminal or the terminal that is spanned by this packed +// node. +// +// This is not intended for the user to inspect and play with. The +// package should provide another function to interpret this data, for +// example to search something or to display it. The reason we don't +// directly return something to display is that the plain forest might +// contain cyclic data, and is inconvenient to represent in Emacs. So +// we only try to display this information to the user if the need +// arises. + +#[derive(Debug, Clone)] +#[repr(C)] +pub struct Parser { + g: Grammar, + gi: GrammarInfo, + stparser: STDAGParser<PFS, ParseForest, PFRecorder>, +} + +impl Parser { + fn new(gs: &str) -> Result<Self, Box<dyn std::error::Error>> { + let g: Grammar = gs.parse()?; + + let mut stparser = STDAGParser::new(); + + let mut gi = g.generate_info()?; + + stparser.init(&g, &mut gi)?; + + Ok(Self { g, gi, stparser }) + } +} + +#[no_mangle] +extern "C" fn new_parser( + gs: *mut std::os::raw::c_char, + error: *mut std::os::raw::c_int, +) -> *mut Parser { + let parsed_str; + let parser_result; + + unsafe { + let cstr = std::ffi::CStr::from_ptr(gs).to_str(); + + if cstr.is_err() { + *error = 1; + return std::ptr::null_mut(); + } + + parsed_str = cstr.unwrap().to_owned(); + + parser_result = Parser::new(&parsed_str); + + if parser_result.is_err() { + *error = 2; + eprintln!("failed: {parser_result:?}"); + return std::ptr::null_mut(); + } + + *error = 0; + } + + Box::into_raw(Box::new(parser_result.unwrap())) +} + +#[no_mangle] +extern "C" fn clean_parser(parser: *const std::ffi::c_void) { + unsafe { + Box::from_raw(parser as *mut Parser); + } +} + +// #[no_mangle] +// extern "C" fn reset_parser(parser: *mut Parser) { +// let mut parser_box; +// unsafe { +// parser_box = Box::from_raw(parser); +// } + +// parser_box +// .stparser +// .init(&parser_box.g, &parser_box.gi) +// .unwrap(); + +// std::mem::forget(parser_box); +// } + +// FIXME: Use a pointer to int to indicate the type of errors, and use +// a pointer to a custom error struct to convey the error messages. +#[no_mangle] +extern "C" fn parser_parse( + parser: *mut Parser, + file: *const std::os::raw::c_char, +) -> std::os::raw::c_int { + let mut parser_box; + let cstr; + + unsafe { + parser_box = Box::from_raw(parser); + cstr = std::ffi::CStr::from_ptr(file).to_str(); + + if cstr.is_err() { + eprintln!("error reading string: {:?}", cstr); + return 0; + } + } + + parser_box.stparser.reinit(); + + let file_string = std::fs::read_to_string(cstr.unwrap()); + + if file_string.is_err() { + eprintln!("error reading file: {:?}", file_string); + return 0; + } + + let file_string = file_string.unwrap(); + + let parse_result = parser_box + .stparser + .parse(&file_string.chars().collect::<Vec<_>>()); + + if parse_result.is_err() { + eprintln!("failed to parse: {:?}", parse_result); + return 0; + } + + let (accepting, _) = parse_result.unwrap(); + + std::mem::forget(parser_box); + + accepting as std::os::raw::c_int +} + +#[no_mangle] +extern "C" fn parser_parse_string( + parser: *mut Parser, + input: *const std::os::raw::c_char, +) -> std::os::raw::c_int { + let mut parser_box; + let cstr; + + unsafe { + parser_box = Box::from_raw(parser); + cstr = std::ffi::CStr::from_ptr(input).to_str(); + + if cstr.is_err() { + eprintln!("error reading string: {:?}", cstr); + return 0; + } + } + + parser_box.stparser.reinit(); + + let file_string = cstr.unwrap().to_owned(); + + let parse_result = parser_box + .stparser + .parse(&file_string.chars().collect::<Vec<_>>()); + + if parse_result.is_err() { + eprintln!("failed to parse: {:?}", parse_result); + return 0; + } + + let (accepting, _) = parse_result.unwrap(); + + std::mem::forget(parser_box); + + accepting as std::os::raw::c_int +} |