summaryrefslogtreecommitdiff
path: root/src/old binding.txt
diff options
context:
space:
mode:
authorJSDurand <mmemmew@gmail.com>2023-07-08 12:30:21 +0800
committerJSDurand <mmemmew@gmail.com>2023-07-08 12:31:13 +0800
commit9a317e56f8a6126583f7d0c431bf878d9b1fe7b1 (patch)
tree7bb6004196b38446a5ab0cb3a0ab642d35f113e9 /src/old binding.txt
parent691f969eb104fa3d4c2a1667693fd0382eb9d6b5 (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.txt218
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
+}