Author SHA1 Message Date
josh 193666d499 Test multiple starting rules 2026-02-09 21:18:32 -05:00
josh 5187cff24d Add p_parse_*() API for each start rule 2026-02-09 17:58:47 -05:00
josh 87890a3d77 Add p_result_*() and p_free_ast_*() functions for each start node 2026-02-09 16:52:15 -05:00
josh 7122bdc2db wip 2026-02-08 22:22:27 -05:00
101 changed files with 1243 additions and 2537 deletions

No files matched your search

-73
View File
@@ -1,76 +1,3 @@
## v4.5.0
### New Features
- Add `noline` grammar statement to skip emitting `#line` directives
- Attempt to autodetect target language (D/C++) in extra/vim/syntax/propane.vim
### Fixes
- Fix #line reset directives
- Update keyword list in extra/vim/syntax/propane.vim
- Fix propane.vim keyword detection
## v4.4.0
### New Features
- Add p_value_get() / p_value_get_XXX() accessors
## v4.3.0
### New Features
- Use #line for user code blocks to report input grammar position for errors.
## v4.2.0
### New Features
- Add support for a custom lex function.
## v4.1.0
### New Features
- Add `p_context_delete()` and `p_tree_delete()` for D targets.
## v4.0.0
### New Features
- Add `context_user_fields` statement to allow custom context user fields.
- Add `token_user_fields` statement to allow custom token user fields.
- Add `on_token_node` statement to allow custom code when constructing token nodes.
- Add `free_token_node` statement to allow custom code when freeing token nodes.
- Add `p_context_delete()`.
- Allow `drop` patterns to execute lexer user code blocks.
### Breaking Changes
- Replace `p_context_init()` with `p_context_new()` and `p_context_delete()`.
- Renamed `p_free_tree()` to `p_tree_delete()`.
- The `free_token_node` statement now takes a user code block instead of a
function name parameter.
## v3.0.0
### New Features
- Add support for multiple starting rules (#38)
- Add `p_free_tree()` functions to reclaim generated tree memory
- Add `free_token_node` grammar statement to reclaim user-allocated memory stored in a Token tree node `pvalue` field
- Add valgrind memory leak tests to unit tests
- Fix build issues for C++ to officially support C++ target output
### Improvements
- Document `p_lex()` and `p_token_info_t` in user guide (#37)
### Breaking Changes
- Rename AST generation mode to tree generation mode (see [UPGRADING.md](UPGRADING.md))
## v2.3.0 ## v2.3.0
### New Features ### New Features
+7 -7
View File
@@ -5,12 +5,12 @@ GEM
date (3.5.1) date (3.5.1)
diff-lcs (1.6.2) diff-lcs (1.6.2)
docile (1.4.1) docile (1.4.1)
erb (6.0.4) erb (6.0.1)
psych (5.4.0) psych (5.3.1)
date date
stringio stringio
rake (13.4.2) rake (13.3.1)
rdoc (7.2.0) rdoc (7.1.0)
erb erb
psych (>= 4.0.0) psych (>= 4.0.0)
tsort tsort
@@ -24,10 +24,10 @@ GEM
rspec-expectations (3.13.5) rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-mocks (3.13.8) rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-support (3.13.7) rspec-support (3.13.6)
simplecov (0.22.0) simplecov (0.22.0)
docile (~> 1.1) docile (~> 1.1)
simplecov-html (~> 0.11) simplecov-html (~> 0.11)
@@ -51,4 +51,4 @@ DEPENDENCIES
syntax syntax
BUNDLED WITH BUNDLED WITH
4.0.14 2.3.7
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2010-2026 Josh Holtrop Copyright (c) 2010-2024 Josh Holtrop
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+1 -3
View File
@@ -7,9 +7,7 @@ Propane is a LALR Parser Generator (LPG) which:
* supports UTF-8 lexer inputs * supports UTF-8 lexer inputs
* generates a table-driven shift/reduce parser to parse input in linear time * generates a table-driven shift/reduce parser to parse input in linear time
* targets C, C++, or D language outputs * targets C, C++, or D language outputs
* optionally supports automatic full parse tree generation * optionally supports automatic full AST generation
* supports starting parsing from multiple start rules
* tracks input text start and end positions for all matched tokens/rules
* is MIT-licensed * is MIT-licensed
* is distributable as a standalone Ruby script * is distributable as a standalone Ruby script
-21
View File
@@ -1,21 +0,0 @@
## v4.0.0
### API Changes
- Replace any calls to `p_context_init()` with `p_context_new()`.
- Replace any references to the address of a statically allocated context
structure with the pointer returned from `p_context_init()` (e.g. `&context`
-> `context`).
- Add a call to `p_context_delete()` (for C or C++) after lexing/parsing to
reclaim context memory.
- Rename `p_free_tree()` calls to `p_tree_delete()`.
- Change `free_token_node` statement calls from taking a function name argument
to taking a user code block.
## v3.0.0
### Grammar Changes
- Rename `ast;` statement to `tree;`.
- Rename `ast_prefix;` statement to `tree_prefix;`.
- Rename `ast_suffix;` statement to `tree_suffix;`.
+67 -99
View File
@@ -43,52 +43,30 @@ const char * <%= @grammar.prefix %>token_names[] = {
*************************************************************************/ *************************************************************************/
/** /**
* Allocate and initialize lexer/parser context structure. * Initialize lexer/parser context structure.
*
* Deinitialize and deallocate with <%= @grammar.prefix %>context_delete().
* *
* @param[out] context
* Lexer/parser context structure.
* @param input * @param input
* Text input. * Text input.
* @param input_length * @param input_length
* Text input length. * Text input length.
*
* @return Context structure for lexer/parser.
*/ */
<%= @grammar.prefix %>context_t * <%= @grammar.prefix %>context_new(uint8_t const * input, size_t input_length) void <%= @grammar.prefix %>context_init(<%= @grammar.prefix %>context_t * context, uint8_t const * input, size_t input_length)
{ {
<% if @cpp %> /* New default-initialized context structure. */
<%= @grammar.prefix %>context_t * context = new <%= @grammar.prefix %>context_t(); <%= @grammar.prefix %>context_t newcontext;
<% else %> memset(&newcontext, 0, sizeof(newcontext));
<%= @grammar.prefix %>context_t * context = (<%= @grammar.prefix %>context_t *)calloc(1, sizeof(<%= @grammar.prefix %>context_t));
<% end %>
/* Lexer initialization. */ /* Lexer initialization. */
context->input = input; newcontext.input = input;
context->input_length = input_length; newcontext.input_length = input_length;
context->text_position.row = 1u; newcontext.text_position.row = 1u;
context->text_position.col = 1u; newcontext.text_position.col = 1u;
context->mode = <%= @lexer.mode_id("default") %>; newcontext.mode = <%= @lexer.mode_id("default") %>;
return context; /* Copy to the user's context structure. */
} *context = newcontext;
/**
* Deinitialize and deallocate lexer/parser context structure.
*
* For C++, destructors will be called for any context user fields. However, if
* pointers are used to store allocated resources, the user should free them
* before calling this function.
*
* @param context
* Lexer/parser context structure allocated with <%= @grammar.prefix %>context_new().
*/
void <%= @grammar.prefix %>context_delete(<%= @grammar.prefix %>context_t * context)
{
<% if @cpp %>
delete context;
<% else %>
free(context);
<% end %>
} }
/************************************************************************** /**************************************************************************
@@ -660,7 +638,7 @@ typedef struct
* reduce action. * reduce action.
*/ */
parser_state_id_t n_states; parser_state_id_t n_states;
<% if @grammar.tree %> <% if @grammar.ast %>
/** /**
* Map of rule components to rule set child fields. * Map of rule components to rule set child fields.
@@ -668,7 +646,7 @@ typedef struct
uint16_t const * rule_set_node_field_index_map; uint16_t const * rule_set_node_field_index_map;
/** /**
* Number of rule set tree node fields. * Number of rule set AST node fields.
*/ */
uint16_t rule_set_node_field_array_size; uint16_t rule_set_node_field_array_size;
@@ -710,23 +688,21 @@ typedef struct
/** Parser value from this state. */ /** Parser value from this state. */
<%= @grammar.prefix %>value_t pvalue; <%= @grammar.prefix %>value_t pvalue;
<% if @grammar.tree %> <% if @grammar.ast %>
/** tree node. */ /** AST node. */
void * tree_node; void * ast_node;
<% end %> <% end %>
} state_value_t; } state_value_t;
<% if @grammar.tree %> /** Common AST node structure. */
/** Common tree node structure. */ typedef struct ASTNode_s
typedef struct TreeNode_s
{ {
<%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t position;
<%= @grammar.prefix %>position_t end_position; <%= @grammar.prefix %>position_t end_position;
uint16_t n_fields; uint16_t n_fields;
uint8_t is_token; uint8_t is_token;
struct TreeNode_s * fields[]; struct ASTNode_s * fields[];
} TreeNode; } ASTNode;
<% end %>
/** Parser shift table. */ /** Parser shift table. */
static const shift_t parser_shift_table[] = { static const shift_t parser_shift_table[] = {
@@ -735,7 +711,7 @@ static const shift_t parser_shift_table[] = {
<% end %> <% end %>
}; };
<% if @grammar.tree %> <% if @grammar.ast %>
<% @grammar.rules.each do |rule| %> <% @grammar.rules.each do |rule| %>
<% unless rule.flat_rule_set_node_field_index_map? %> <% unless rule.flat_rule_set_node_field_index_map? %>
const uint16_t r_<%= rule.name.gsub("$", "_") %><%= rule.id %>_node_field_index_map[<%= rule.rule_set_node_field_index_map.size %>] = {<%= rule.rule_set_node_field_index_map.map {|v| v.to_s}.join(", ") %>}; const uint16_t r_<%= rule.name.gsub("$", "_") %><%= rule.id %>_node_field_index_map[<%= rule.rule_set_node_field_index_map.size %>] = {<%= rule.rule_set_node_field_index_map.map {|v| v.to_s}.join(", ") %>};
@@ -750,14 +726,14 @@ static const reduce_t parser_reduce_table[] = {
<%= reduce[:token_id] %>u, /* Token: <%= reduce[:token] ? reduce[:token].name : "(any)" %> */ <%= reduce[:token_id] %>u, /* Token: <%= reduce[:token] ? reduce[:token].name : "(any)" %> */
<%= reduce[:rule_id] %>u, /* Rule ID */ <%= reduce[:rule_id] %>u, /* Rule ID */
<%= reduce[:rule_set_id] %>u, /* Rule set ID (<%= reduce[:rule].rule_set.name %>) */ <%= reduce[:rule_set_id] %>u, /* Rule set ID (<%= reduce[:rule].rule_set.name %>) */
<% if @grammar.tree %> <% if @grammar.ast %>
<%= reduce[:n_states] %>u, /* Number of states */ <%= reduce[:n_states] %>u, /* Number of states */
<% if reduce[:rule].flat_rule_set_node_field_index_map? %> <% if reduce[:rule].flat_rule_set_node_field_index_map? %>
NULL, /* No rule set node field index map (flat map) */ NULL, /* No rule set node field index map (flat map) */
<% else %> <% else %>
&r_<%= reduce[:rule].name.gsub("$", "_") %><%= reduce[:rule].id %>_node_field_index_map[0], /* Rule set node field index map */ &r_<%= reduce[:rule].name.gsub("$", "_") %><%= reduce[:rule].id %>_node_field_index_map[0], /* Rule set node field index map */
<% end %> <% end %>
<%= reduce[:rule].rule_set.tree_fields.size %>, /* Number of tree fields */ <%= reduce[:rule].rule_set.ast_fields.size %>, /* Number of AST fields */
<%= reduce[:propagate_optional_target] %>}, /* Propagate optional target? */ <%= reduce[:propagate_optional_target] %>}, /* Propagate optional target? */
<% else %> <% else %>
<%= reduce[:n_states] %>u}, <%= reduce[:n_states] %>u},
@@ -865,7 +841,7 @@ static void state_values_stack_free(state_values_stack_t * stack)
free(stack->entries); free(stack->entries);
} }
<% unless @grammar.tree %> <% unless @grammar.ast %>
/** /**
* Execute user code associated with a parser rule. * Execute user code associated with a parser rule.
* *
@@ -968,7 +944,7 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start
<%= @grammar.prefix %>token_t token = INVALID_TOKEN_ID; <%= @grammar.prefix %>token_t token = INVALID_TOKEN_ID;
state_values_stack_t statevalues; state_values_stack_t statevalues;
size_t reduced_rule_set = INVALID_ID; size_t reduced_rule_set = INVALID_ID;
<% if @grammar.tree %> <% if @grammar.ast %>
void * reduced_parser_node; void * reduced_parser_node;
<% else %> <% else %>
<%= @grammar.prefix %>value_t reduced_parser_value; <%= @grammar.prefix %>value_t reduced_parser_value;
@@ -981,7 +957,7 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start
{ {
if (token == INVALID_TOKEN_ID) if (token == INVALID_TOKEN_ID)
{ {
size_t lexer_result = <%= lex_fn %>(context, &token_info); size_t lexer_result = <%= @grammar.prefix %>lex(context, &token_info);
if (lexer_result != P_SUCCESS) if (lexer_result != P_SUCCESS)
{ {
result = lexer_result; result = lexer_result;
@@ -1000,8 +976,8 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start
if ((shift_state != INVALID_ID) && (token == TOKEN___EOF)) if ((shift_state != INVALID_ID) && (token == TOKEN___EOF))
{ {
/* Successful parse. */ /* Successful parse. */
<% if @grammar.tree %> <% if @grammar.ast %>
context->parse_result = state_values_stack_index(&statevalues, -1)->tree_node; context->parse_result = state_values_stack_index(&statevalues, -1)->ast_node;
<% else %> <% else %>
context->parse_result = state_values_stack_index(&statevalues, -1)->pvalue; context->parse_result = state_values_stack_index(&statevalues, -1)->pvalue;
<% end %> <% end %>
@@ -1017,20 +993,15 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start
if (reduced_rule_set == INVALID_ID) if (reduced_rule_set == INVALID_ID)
{ {
/* We shifted a token, mark it consumed. */ /* We shifted a token, mark it consumed. */
<% if @grammar.tree %> <% if @grammar.ast %>
<% if @cpp %> <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> * token_ast_node = (<%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> *)malloc(sizeof(<%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>));
<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> * token_tree_node = new <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>(); token_ast_node->position = token_info.position;
<% else %> token_ast_node->end_position = token_info.end_position;
<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> * token_tree_node = (<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> *)malloc(sizeof(<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>)); token_ast_node->n_fields = 0u;
<% end %> token_ast_node->is_token = 1u;
token_tree_node->position = token_info.position; token_ast_node->token = token;
token_tree_node->end_position = token_info.end_position; token_ast_node->pvalue = token_info.pvalue;
token_tree_node->n_fields = 0u; state_values_stack_index(&statevalues, -1)->ast_node = token_ast_node;
token_tree_node->is_token = 1u;
token_tree_node->token = token;
token_tree_node->pvalue = token_info.pvalue;
<%= expand_code(@grammar.on_token_node, false, nil, nil) %>
state_values_stack_index(&statevalues, -1)->tree_node = token_tree_node;
<% else %> <% else %>
state_values_stack_index(&statevalues, -1)->pvalue = token_info.pvalue; state_values_stack_index(&statevalues, -1)->pvalue = token_info.pvalue;
<% end %> <% end %>
@@ -1039,8 +1010,8 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start
else else
{ {
/* We shifted a RuleSet. */ /* We shifted a RuleSet. */
<% if @grammar.tree %> <% if @grammar.ast %>
state_values_stack_index(&statevalues, -1)->tree_node = reduced_parser_node; state_values_stack_index(&statevalues, -1)->ast_node = reduced_parser_node;
<% else %> <% else %>
state_values_stack_index(&statevalues, -1)->pvalue = reduced_parser_value; state_values_stack_index(&statevalues, -1)->pvalue = reduced_parser_value;
<%= @grammar.prefix %>value_t new_parse_result; <%= @grammar.prefix %>value_t new_parse_result;
@@ -1056,16 +1027,16 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start
if (reduce_index != INVALID_ID) if (reduce_index != INVALID_ID)
{ {
/* We have something to reduce. */ /* We have something to reduce. */
<% if @grammar.tree %> <% if @grammar.ast %>
if (parser_reduce_table[reduce_index].propagate_optional_target) if (parser_reduce_table[reduce_index].propagate_optional_target)
{ {
reduced_parser_node = state_values_stack_index(&statevalues, -1)->tree_node; reduced_parser_node = state_values_stack_index(&statevalues, -1)->ast_node;
} }
else if (parser_reduce_table[reduce_index].n_states > 0) else if (parser_reduce_table[reduce_index].n_states > 0)
{ {
size_t n_fields = parser_reduce_table[reduce_index].rule_set_node_field_array_size; size_t n_fields = parser_reduce_table[reduce_index].rule_set_node_field_array_size;
size_t bytes = sizeof(TreeNode) + n_fields * sizeof(void *); size_t bytes = sizeof(ASTNode) + n_fields * sizeof(void *);
TreeNode * node = (TreeNode *)malloc(bytes); ASTNode * node = (ASTNode *)malloc(bytes);
memset(node, 0, bytes); memset(node, 0, bytes);
node->position = INVALID_POSITION; node->position = INVALID_POSITION;
node->end_position = INVALID_POSITION; node->end_position = INVALID_POSITION;
@@ -1074,20 +1045,20 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start
{ {
for (size_t i = 0; i < parser_reduce_table[reduce_index].n_states; i++) for (size_t i = 0; i < parser_reduce_table[reduce_index].n_states; i++)
{ {
node->fields[i] = (TreeNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->tree_node; node->fields[i] = (ASTNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->ast_node;
} }
} }
else else
{ {
for (size_t i = 0; i < parser_reduce_table[reduce_index].n_states; i++) for (size_t i = 0; i < parser_reduce_table[reduce_index].n_states; i++)
{ {
node->fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = (TreeNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->tree_node; node->fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = (ASTNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->ast_node;
} }
} }
bool position_found = false; bool position_found = false;
for (size_t i = 0; i < n_fields; i++) for (size_t i = 0; i < n_fields; i++)
{ {
TreeNode * child = node->fields[i]; ASTNode * child = node->fields[i];
if ((child != NULL) && <%= @grammar.prefix %>position_valid(child->position)) if ((child != NULL) && <%= @grammar.prefix %>position_valid(child->position))
{ {
if (!position_found) if (!position_found)
@@ -1154,15 +1125,15 @@ size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix %>conte
* *
* @return Parse result value. * @return Parse result value.
*/ */
<% if @grammar.tree %> <% if @grammar.ast %>
<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context) <%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context)
{ {
return (<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> *) context->parse_result; return (<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> *) context->parse_result;
} }
<% @grammar.start_rules.each_with_index do |start_rule, i| %> <% @grammar.start_rules.each_with_index do |start_rule, i| %>
<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context) <%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context)
{ {
return (<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> *) context->parse_result; return (<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> *) context->parse_result;
} }
<% end %> <% end %>
<% else %> <% else %>
@@ -1213,19 +1184,16 @@ size_t <%= @grammar.prefix %>user_terminate_code(<%= @grammar.prefix %>context_t
{ {
return context->token; return context->token;
} }
<% if @grammar.tree %> <% if @grammar.ast %>
static void tree_delete(TreeNode * node) static void free_ast_node(ASTNode * node)
{ {
if (node->is_token) if (node->is_token)
{ {
<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> * token_tree_node = (<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> *)node; <% if @grammar.free_token_node %>
<%= expand_code(@grammar.free_token_node, false, nil, nil) %> <%= @grammar.free_token_node %>((<%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> *) node);
<% if @cpp %>
delete token_tree_node;
<% else %>
free(token_tree_node);
<% end %> <% end %>
/* TODO: free value_t */
} }
else if (node->n_fields > 0u) else if (node->n_fields > 0u)
{ {
@@ -1233,28 +1201,28 @@ static void tree_delete(TreeNode * node)
{ {
if (node->fields[i] != NULL) if (node->fields[i] != NULL)
{ {
tree_delete(node->fields[i]); free_ast_node(node->fields[i]);
}
} }
} }
free(node); free(node);
} }
}
/** /**
* Free all tree node memory. * Free all AST node memory.
*/ */
void <%= @grammar.prefix %>tree_delete(<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * tree) void <%= @grammar.prefix %>free_ast(<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * ast)
{ {
tree_delete((TreeNode *)tree); free_ast_node((ASTNode *)ast);
} }
<% @grammar.start_rules.each_with_index do |start_rule, i| %> <% @grammar.start_rules.each_with_index do |start_rule, i| %>
/** /**
* Free all tree node memory. * Free all AST node memory.
*/ */
void <%= @grammar.prefix %>tree_delete_<%= start_rule %>(<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * tree) void <%= @grammar.prefix %>free_ast_<%= start_rule %>(<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * ast)
{ {
tree_delete((TreeNode *)tree); free_ast_node((ASTNode *)ast);
} }
<% end %> <% end %>
<% end %> <% end %>
+52 -122
View File
@@ -9,7 +9,7 @@ module <%= @grammar.modulename %>;
<% end %> <% end %>
import core.memory; import core.memory;
import core.stdc.stdlib : malloc, free; import core.stdc.stdlib : malloc;
/************************************************************************** /**************************************************************************
* User code blocks * User code blocks
@@ -75,7 +75,7 @@ public struct <%= @grammar.prefix %>position_t
} }
} }
<% if @grammar.tree %> <% if @grammar.ast %>
/** Parser values type. */ /** Parser values type. */
public alias <%= @grammar.prefix %>value_t = <%= @grammar.ptype %>; public alias <%= @grammar.prefix %>value_t = <%= @grammar.ptype %>;
<% else %> <% else %>
@@ -86,58 +86,35 @@ public union <%= @grammar.prefix %>value_t
<%= typestring %> v_<%= name %>; <%= typestring %> v_<%= name %>;
<% end %> <% end %>
} }
/** Parser value constructor(s). */
<% @grammar.ptypes.each do |name, typestring| %>
public <%= @grammar.prefix %>value_t <%= @grammar.prefix %>value<%= name == "default" ? "" : "_#{name}" %>(T)(T v)
{
return <%= @grammar.prefix %>value_t(v_<%= name %>: v);
}
<% end %> <% end %>
/** Parser value accessor(s). */ <% if @grammar.ast %>
<% @grammar.ptypes.each do |name, typestring| %> /** Common AST node structure. */
public <%= typestring %> <%= @grammar.prefix %>value_get<%= name == "default" ? "" : "_#{name}" %>(<%= @grammar.prefix %>value_t * pvalue) private struct ASTNode
{
return pvalue.v_<%= name %>;
}
<% end %>
<% end %>
<% if @grammar.tree %>
/** Common tree node structure. */
private struct TreeNode
{ {
<%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t position;
<%= @grammar.prefix %>position_t end_position; <%= @grammar.prefix %>position_t end_position;
ushort n_fields;
bool is_token;
void *[0] fields; void *[0] fields;
} }
/** Tree node types. @{ */ /** AST node types. @{ */
public struct <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> public struct <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>
{ {
/* TreeNode fields must be present in the same order here. */ /* ASTNode fields must be present in the same order here. */
<%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t position;
<%= @grammar.prefix %>position_t end_position; <%= @grammar.prefix %>position_t end_position;
ushort n_fields;
bool is_token;
<%= @grammar.prefix %>token_t token; <%= @grammar.prefix %>token_t token;
<%= @grammar.prefix %>value_t pvalue; <%= @grammar.prefix %>value_t pvalue;
<%= @grammar.token_user_fields %>
} }
<% @parser.rule_sets.each do |name, rule_set| %> <% @parser.rule_sets.each do |name, rule_set| %>
<% next if name.start_with?("$") %> <% next if name.start_with?("$") %>
<% next if rule_set.optional? %> <% next if rule_set.optional? %>
public struct <%= @grammar.tree_prefix %><%= name %><%= @grammar.tree_suffix %> public struct <%= @grammar.ast_prefix %><%= name %><%= @grammar.ast_suffix %>
{ {
<%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t position;
<%= @grammar.prefix %>position_t end_position; <%= @grammar.prefix %>position_t end_position;
ushort n_fields; <% rule_set.ast_fields.each do |fields| %>
bool is_token;
<% rule_set.tree_fields.each do |fields| %>
union union
{ {
<% fields.each do |field_name, type| %> <% fields.each do |field_name, type| %>
@@ -195,7 +172,7 @@ public struct <%= @grammar.prefix %>context_t
/* Parser context data. */ /* Parser context data. */
/** Parse result value. */ /** Parse result value. */
<% if @grammar.tree %> <% if @grammar.ast %>
void * parse_result; void * parse_result;
<% else %> <% else %>
<%= @grammar.prefix %>value_t parse_result; <%= @grammar.prefix %>value_t parse_result;
@@ -206,8 +183,6 @@ public struct <%= @grammar.prefix %>context_t
/** User terminate code. */ /** User terminate code. */
size_t user_terminate_code; size_t user_terminate_code;
<%= @grammar.context_user_fields %>
} }
/************************************************************************** /**************************************************************************
@@ -247,39 +222,26 @@ private enum size_t INVALID_ID = cast(size_t)-1;
*************************************************************************/ *************************************************************************/
/** /**
* Allocate and initialize lexer/parser context structure. * Initialize lexer/parser context structure.
*
* Deinitialize and deallocate with <%= @grammar.prefix %>context_delete().
* *
* @param[out] context
* Lexer/parser context structure.
* @param input * @param input
* Text input. * Text input.
* @param input_length
* Text input length.
*
* @return Context structure for lexer/parser.
*/ */
<%= @grammar.prefix %>context_t * <%= @grammar.prefix %>context_new(string input) public void <%= @grammar.prefix %>context_init(<%= @grammar.prefix %>context_t * context, string input)
{ {
/* New default-initialized context structure. */ /* New default-initialized context structure. */
<%= @grammar.prefix %>context_t * context = new <%= @grammar.prefix %>context_t; <%= @grammar.prefix %>context_t newcontext;
/* Lexer initialization. */ /* Lexer initialization. */
context.input = input; newcontext.input = input;
context.text_position.row = 1u; newcontext.text_position.row = 1u;
context.text_position.col = 1u; newcontext.text_position.col = 1u;
context.mode = <%= @lexer.mode_id("default") %>; newcontext.mode = <%= @lexer.mode_id("default") %>;
return context; /* Copy to the user's context structure. */
} *context = newcontext;
/**
* Deinitialize and deallocate lexer/parser context structure.
*
* @param context
* Lexer/parser context structure allocated with <%= @grammar.prefix %>context_new().
*/
void <%= @grammar.prefix %>context_delete(<%= @grammar.prefix %>context_t * context)
{
} }
/************************************************************************** /**************************************************************************
@@ -835,7 +797,7 @@ private struct reduce_t
* reduce action. * reduce action.
*/ */
parser_state_id_t n_states; parser_state_id_t n_states;
<% if @grammar.tree %> <% if @grammar.ast %>
/** /**
* Map of rule components to rule set child fields. * Map of rule components to rule set child fields.
@@ -843,7 +805,7 @@ private struct reduce_t
immutable(ushort) * rule_set_node_field_index_map; immutable(ushort) * rule_set_node_field_index_map;
/** /**
* Number of rule set tree node fields. * Number of rule set AST node fields.
*/ */
ushort rule_set_node_field_array_size; ushort rule_set_node_field_array_size;
@@ -885,9 +847,9 @@ private struct state_value_t
/** Parser value from this state. */ /** Parser value from this state. */
<%= @grammar.prefix %>value_t pvalue; <%= @grammar.prefix %>value_t pvalue;
<% if @grammar.tree %> <% if @grammar.ast %>
/** Tree node. */ /** AST node. */
void * tree_node; void * ast_node;
<% end %> <% end %>
this(size_t state_id) this(size_t state_id)
@@ -903,7 +865,7 @@ private immutable shift_t[] parser_shift_table = [
<% end %> <% end %>
]; ];
<% if @grammar.tree %> <% if @grammar.ast %>
<% @grammar.rules.each do |rule| %> <% @grammar.rules.each do |rule| %>
<% unless rule.flat_rule_set_node_field_index_map? %> <% unless rule.flat_rule_set_node_field_index_map? %>
immutable ushort[<%= rule.rule_set_node_field_index_map.size %>] r_<%= rule.name.gsub("$", "_") %><%= rule.id %>_node_field_index_map = [<%= rule.rule_set_node_field_index_map.map {|v| v.to_s}.join(", ") %>]; immutable ushort[<%= rule.rule_set_node_field_index_map.size %>] r_<%= rule.name.gsub("$", "_") %><%= rule.id %>_node_field_index_map = [<%= rule.rule_set_node_field_index_map.map {|v| v.to_s}.join(", ") %>];
@@ -918,14 +880,14 @@ private immutable reduce_t[] parser_reduce_table = [
<%= reduce[:token_id] %>u, /* Token: <%= reduce[:token] ? reduce[:token].name : "(any)" %> */ <%= reduce[:token_id] %>u, /* Token: <%= reduce[:token] ? reduce[:token].name : "(any)" %> */
<%= reduce[:rule_id] %>u, /* Rule ID */ <%= reduce[:rule_id] %>u, /* Rule ID */
<%= reduce[:rule_set_id] %>u, /* Rule set ID (<%= reduce[:rule].rule_set.name %>) */ <%= reduce[:rule_set_id] %>u, /* Rule set ID (<%= reduce[:rule].rule_set.name %>) */
<% if @grammar.tree %> <% if @grammar.ast %>
<%= reduce[:n_states] %>u, /* Number of states */ <%= reduce[:n_states] %>u, /* Number of states */
<% if reduce[:rule].flat_rule_set_node_field_index_map? %> <% if reduce[:rule].flat_rule_set_node_field_index_map? %>
null, /* No rule set node field index map (flat map) */ null, /* No rule set node field index map (flat map) */
<% else %> <% else %>
&r_<%= reduce[:rule].name.gsub("$", "_") %><%= reduce[:rule].id %>_node_field_index_map[0], /* Rule set node field index map */ &r_<%= reduce[:rule].name.gsub("$", "_") %><%= reduce[:rule].id %>_node_field_index_map[0], /* Rule set node field index map */
<% end %> <% end %>
<%= reduce[:rule].rule_set.tree_fields.size %>, /* Number of tree fields */ <%= reduce[:rule].rule_set.ast_fields.size %>, /* Number of AST fields */
<%= reduce[:propagate_optional_target] %>), /* Propagate optional target? */ <%= reduce[:propagate_optional_target] %>), /* Propagate optional target? */
<% else %> <% else %>
<%= reduce[:n_states] %>u), /* Number of states */ <%= reduce[:n_states] %>u), /* Number of states */
@@ -940,7 +902,7 @@ private immutable parser_state_t[] parser_state_table = [
<% end %> <% end %>
]; ];
<% unless @grammar.tree %> <% unless @grammar.ast %>
/** /**
* Execute user code associated with a parser rule. * Execute user code associated with a parser rule.
* *
@@ -1044,7 +1006,7 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star
state_value_t[] statevalues = new state_value_t[](1); state_value_t[] statevalues = new state_value_t[](1);
statevalues[0].state_id = start_state_id; statevalues[0].state_id = start_state_id;
size_t reduced_rule_set = INVALID_ID; size_t reduced_rule_set = INVALID_ID;
<% if @grammar.tree %> <% if @grammar.ast %>
void * reduced_parser_node; void * reduced_parser_node;
<% else %> <% else %>
<%= @grammar.prefix %>value_t reduced_parser_value; <%= @grammar.prefix %>value_t reduced_parser_value;
@@ -1053,7 +1015,7 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star
{ {
if (token == INVALID_TOKEN_ID) if (token == INVALID_TOKEN_ID)
{ {
size_t lexer_result = <%= lex_fn %>(context, &token_info); size_t lexer_result = <%= @grammar.prefix %>lex(context, &token_info);
if (lexer_result != P_SUCCESS) if (lexer_result != P_SUCCESS)
{ {
return lexer_result; return lexer_result;
@@ -1071,8 +1033,8 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star
if ((shift_state != INVALID_ID) && (token == TOKEN___EOF)) if ((shift_state != INVALID_ID) && (token == TOKEN___EOF))
{ {
/* Successful parse. */ /* Successful parse. */
<% if @grammar.tree %> <% if @grammar.ast %>
context.parse_result = statevalues[$-1].tree_node; context.parse_result = statevalues[$-1].ast_node;
<% else %> <% else %>
context.parse_result = statevalues[$-1].pvalue; context.parse_result = statevalues[$-1].pvalue;
<% end %> <% end %>
@@ -1086,10 +1048,9 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star
if (reduced_rule_set == INVALID_ID) if (reduced_rule_set == INVALID_ID)
{ {
/* We shifted a token, mark it consumed. */ /* We shifted a token, mark it consumed. */
<% if @grammar.tree %> <% if @grammar.ast %>
<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> * token_tree_node = new <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>(token_info.position, token_info.end_position, 0u, true, token, token_info.pvalue); <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> * token_ast_node = new <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>(token_info.position, token_info.end_position, token, token_info.pvalue);
<%= expand_code(@grammar.on_token_node, false, nil, nil) %> statevalues[$-1].ast_node = token_ast_node;
statevalues[$-1].tree_node = token_tree_node;
<% else %> <% else %>
statevalues[$-1].pvalue = token_info.pvalue; statevalues[$-1].pvalue = token_info.pvalue;
<% end %> <% end %>
@@ -1098,8 +1059,8 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star
else else
{ {
/* We shifted a RuleSet. */ /* We shifted a RuleSet. */
<% if @grammar.tree %> <% if @grammar.ast %>
statevalues[$-1].tree_node = reduced_parser_node; statevalues[$-1].ast_node = reduced_parser_node;
<% else %> <% else %>
statevalues[$-1].pvalue = reduced_parser_value; statevalues[$-1].pvalue = reduced_parser_value;
<%= @grammar.prefix %>value_t new_parse_result; <%= @grammar.prefix %>value_t new_parse_result;
@@ -1114,21 +1075,19 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star
if (reduce_index != INVALID_ID) if (reduce_index != INVALID_ID)
{ {
/* We have something to reduce. */ /* We have something to reduce. */
<% if @grammar.tree %> <% if @grammar.ast %>
if (parser_reduce_table[reduce_index].propagate_optional_target) if (parser_reduce_table[reduce_index].propagate_optional_target)
{ {
reduced_parser_node = statevalues[$ - 1].tree_node; reduced_parser_node = statevalues[$ - 1].ast_node;
} }
else if (parser_reduce_table[reduce_index].n_states > 0) else if (parser_reduce_table[reduce_index].n_states > 0)
{ {
size_t n_fields = parser_reduce_table[reduce_index].rule_set_node_field_array_size; size_t n_fields = parser_reduce_table[reduce_index].rule_set_node_field_array_size;
size_t node_size = TreeNode.sizeof + n_fields * (void *).sizeof; size_t node_size = ASTNode.sizeof + n_fields * (void *).sizeof;
TreeNode * node = cast(TreeNode *)malloc(node_size); ASTNode * node = cast(ASTNode *)malloc(node_size);
GC.addRange(node, node_size); GC.addRange(node, node_size);
node.position = <%= @grammar.prefix %>position_t.INVALID; node.position = <%= @grammar.prefix %>position_t.INVALID;
node.end_position = <%= @grammar.prefix %>position_t.INVALID; node.end_position = <%= @grammar.prefix %>position_t.INVALID;
node.n_fields = cast(ushort)n_fields;
node.is_token = false;
foreach (i; 0..n_fields) foreach (i; 0..n_fields)
{ {
node.fields[i] = null; node.fields[i] = null;
@@ -1137,20 +1096,20 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star
{ {
foreach (i; 0..parser_reduce_table[reduce_index].n_states) foreach (i; 0..parser_reduce_table[reduce_index].n_states)
{ {
node.fields[i] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].tree_node; node.fields[i] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].ast_node;
} }
} }
else else
{ {
foreach (i; 0..parser_reduce_table[reduce_index].n_states) foreach (i; 0..parser_reduce_table[reduce_index].n_states)
{ {
node.fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].tree_node; node.fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].ast_node;
} }
} }
bool position_found = false; bool position_found = false;
foreach (i; 0..n_fields) foreach (i; 0..n_fields)
{ {
TreeNode * child = cast(TreeNode *)node.fields[i]; ASTNode * child = cast(ASTNode *)node.fields[i];
if (child && child.position.valid) if (child && child.position.valid)
{ {
if (!position_found) if (!position_found)
@@ -1212,15 +1171,15 @@ public size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix
* *
* @return Parse result value. * @return Parse result value.
*/ */
<% if @grammar.tree %> <% if @grammar.ast %>
public <%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context) public <%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context)
{ {
return cast(<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> *)context.parse_result; return cast(<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> *)context.parse_result;
} }
<% @grammar.start_rules.each_with_index do |start_rule, i| %> <% @grammar.start_rules.each_with_index do |start_rule, i| %>
public <%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context) public <%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context)
{ {
return cast(<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> *)context.parse_result; return cast(<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> *)context.parse_result;
} }
<% end %> <% end %>
<% else %> <% else %>
@@ -1236,35 +1195,6 @@ public <%= start_rule_type(i)[1] %> <%= @grammar.prefix %>result_<%= start_rule
<% end %> <% end %>
<% end %> <% end %>
<% if @grammar.tree %>
private void tree_delete(TreeNode * node)
{
if (!node.is_token)
{
for (size_t i = 0u; i < node.n_fields; i++)
{
if (node.fields[i])
{
tree_delete(cast(TreeNode *)node.fields[i]);
}
}
GC.removeRange(node);
free(node);
}
}
void <%= @grammar.prefix %>tree_delete(<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * tree)
{
tree_delete(cast(TreeNode *)tree);
}
<% @grammar.start_rules.each_with_index do |start_rule, i| %>
void <%= @grammar.prefix %>tree_delete_<%= start_rule %>(<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * tree)
{
tree_delete(cast(TreeNode *)tree);
}
<% end %>
<% end %>
/** /**
* Get the current text input position. * Get the current text input position.
* *
+18 -39
View File
@@ -58,7 +58,7 @@ typedef struct
/** User header code blocks. */ /** User header code blocks. */
<%= @grammar.code_blocks.fetch("header", "") %> <%= @grammar.code_blocks.fetch("header", "") %>
<% if @grammar.tree %> <% if @grammar.ast %>
/** Parser values type. */ /** Parser values type. */
typedef <%= @grammar.ptype %> <%= @grammar.prefix %>value_t; typedef <%= @grammar.ptype %> <%= @grammar.prefix %>value_t;
<% else %> <% else %>
@@ -69,37 +69,20 @@ typedef union
<%= typestring %> v_<%= name %>; <%= typestring %> v_<%= name %>;
<% end %> <% end %>
} <%= @grammar.prefix %>value_t; } <%= @grammar.prefix %>value_t;
/** Parser value constructor(s). */
<% @grammar.ptypes.each do |name, typestring| %>
static inline <%= @grammar.prefix %>value_t <%= @grammar.prefix %>value<%= name == "default" ? "" : "_#{name}" %>(<%= typestring %> v)
{
return (<%= @grammar.prefix %>value_t){.v_<%= name %> = v};
}
<% end %> <% end %>
/** Parser value accessor(s). */ <% if @grammar.ast %>
<% @grammar.ptypes.each do |name, typestring| %> /** AST node types. @{ */
static inline <%= typestring %> <%= @grammar.prefix %>value_get<%= name == "default" ? "" : "_#{name}" %>(<%= @grammar.prefix %>value_t const * pvalue) typedef struct <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>
{ {
return pvalue->v_<%= name %>; <% # ASTNode fields must be present in the same order here. # %>
}
<% end %>
<% end %>
<% if @grammar.tree %>
/** Tree node types. @{ */
typedef struct <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>
{
<% # TreeNode fields must be present in the same order here. # %>
<%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t position;
<%= @grammar.prefix %>position_t end_position; <%= @grammar.prefix %>position_t end_position;
uint16_t n_fields; uint16_t n_fields;
uint8_t is_token; uint8_t is_token;
<%= @grammar.token_user_fields %>
<%= @grammar.prefix %>token_t token; <%= @grammar.prefix %>token_t token;
<%= @grammar.prefix %>value_t pvalue; <%= @grammar.prefix %>value_t pvalue;
} <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>; } <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>;
<% @parser.rule_sets.each do |name, rule_set| %> <% @parser.rule_sets.each do |name, rule_set| %>
<% next if name.start_with?("$") %> <% next if name.start_with?("$") %>
@@ -110,14 +93,14 @@ struct <%= name %>;
<% @parser.rule_sets.each do |name, rule_set| %> <% @parser.rule_sets.each do |name, rule_set| %>
<% next if name.start_with?("$") %> <% next if name.start_with?("$") %>
<% next if rule_set.optional? %> <% next if rule_set.optional? %>
typedef struct <%= @grammar.tree_prefix %><%= name %><%= @grammar.tree_suffix %> typedef struct <%= @grammar.ast_prefix %><%= name %><%= @grammar.ast_suffix %>
{ {
<% # TreeNode fields must be present in the same order here. # %> <% # ASTNode fields must be present in the same order here. # %>
<%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t position;
<%= @grammar.prefix %>position_t end_position; <%= @grammar.prefix %>position_t end_position;
uint16_t n_fields; uint16_t n_fields;
uint8_t is_token; uint8_t is_token;
<% rule_set.tree_fields.each do |fields| %> <% rule_set.ast_fields.each do |fields| %>
union union
{ {
<% fields.each do |field_name, type| %> <% fields.each do |field_name, type| %>
@@ -125,7 +108,7 @@ typedef struct <%= @grammar.tree_prefix %><%= name %><%= @grammar.tree_suffix %>
<% end %> <% end %>
}; };
<% end %> <% end %>
} <%= @grammar.tree_prefix %><%= name %><%= @grammar.tree_suffix %>; } <%= @grammar.ast_prefix %><%= name %><%= @grammar.ast_suffix %>;
<% end %> <% end %>
/** @} */ /** @} */
@@ -178,7 +161,7 @@ typedef struct
/* Parser context data. */ /* Parser context data. */
/** Parse result value. */ /** Parse result value. */
<% if @grammar.tree %> <% if @grammar.ast %>
void * parse_result; void * parse_result;
<% else %> <% else %>
<%= @grammar.prefix %>value_t parse_result; <%= @grammar.prefix %>value_t parse_result;
@@ -189,8 +172,6 @@ typedef struct
/** User terminate code. */ /** User terminate code. */
size_t user_terminate_code; size_t user_terminate_code;
<%= @grammar.context_user_fields %>
} <%= @grammar.prefix %>context_t; } <%= @grammar.prefix %>context_t;
/************************************************************************** /**************************************************************************
@@ -200,9 +181,7 @@ typedef struct
/** Token names. */ /** Token names. */
extern const char * <%= @grammar.prefix %>token_names[]; extern const char * <%= @grammar.prefix %>token_names[];
<%= @grammar.prefix %>context_t * <%= @grammar.prefix %>context_new(uint8_t const * input, size_t input_length); void <%= @grammar.prefix %>context_init(<%= @grammar.prefix %>context_t * context, uint8_t const * input, size_t input_length);
void <%= @grammar.prefix %>context_delete(<%= @grammar.prefix %>context_t * context);
size_t <%= @grammar.prefix %>decode_code_point(uint8_t const * input, size_t input_length, size_t <%= @grammar.prefix %>decode_code_point(uint8_t const * input, size_t input_length,
<%= @grammar.prefix %>code_point_t * out_code_point, uint8_t * out_code_point_length); <%= @grammar.prefix %>code_point_t * out_code_point, uint8_t * out_code_point_length);
@@ -214,10 +193,10 @@ size_t <%= @grammar.prefix %>parse(<%= @grammar.prefix %>context_t * context);
size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix %>context_t * context); size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix %>context_t * context);
<% end %> <% end %>
<% if @grammar.tree %> <% if @grammar.ast %>
<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context); <%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context);
<% @grammar.start_rules.each_with_index do |start_rule, i| %> <% @grammar.start_rules.each_with_index do |start_rule, i| %>
<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context); <%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context);
<% end %> <% end %>
<% else %> <% else %>
<%= start_rule_type[1] %> <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context); <%= start_rule_type[1] %> <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context);
@@ -226,10 +205,10 @@ size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix %>conte
<% end %> <% end %>
<% end %> <% end %>
<% if @grammar.tree %> <% if @grammar.ast %>
void <%= @grammar.prefix %>tree_delete(<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * tree); void <%= @grammar.prefix %>free_ast(<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * ast);
<% @grammar.start_rules.each_with_index do |start_rule, i| %> <% @grammar.start_rules.each_with_index do |start_rule, i| %>
void <%= @grammar.prefix %>tree_delete_<%= start_rule %>(<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * tree); void <%= @grammar.prefix %>free_ast_<%= start_rule %>(<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * ast);
<% end %> <% end %>
<% end %> <% end %>
+350 -610
View File
File diff suppressed because it is too large. Load diff
+1 -12
View File
@@ -8,11 +8,7 @@ if exists("b:current_syntax")
endif endif
if !exists("b:propane_subtype") if !exists("b:propane_subtype")
if search('\<import\s\+\%(std\|core\)\.', 'nw') > 0
let b:propane_subtype = "d" let b:propane_subtype = "d"
else
let b:propane_subtype = "cpp"
endif
endif endif
exe "syn include @propaneTarget syntax/".b:propane_subtype.".vim" exe "syn include @propaneTarget syntax/".b:propane_subtype.".vim"
@@ -24,19 +20,12 @@ syn match propaneOperator "->"
syn match propaneFieldAlias ":[a-zA-Z0-9_]\+" contains=propaneFieldOperator syn match propaneFieldAlias ":[a-zA-Z0-9_]\+" contains=propaneFieldOperator
syn match propaneFieldOperator ":" contained syn match propaneFieldOperator ":" contained
syn match propaneOperator "?" syn match propaneOperator "?"
" Keywords that introduce a user-defined name. The name is consumed by syn keyword propaneKeyword ast ast_prefix ast_suffix drop module prefix ptype start token tokenid
" propaneName via nextgroup so a name matching a keyword (e.g. 'token start')
" is not highlighted as a keyword. These must be a match (not syn keyword)
" because a syn keyword always wins over a contained nextgroup match.
syn match propaneNameDecl "\<\%(tokenid\|token\|lex_fn\|module\|start\|tree_prefix\|tree_suffix\)\>" nextgroup=propaneName skipwhite
syn match propaneName "\<\h\w*\>" contained
syn match propaneKeyword "\<\%(context_user_fields\|drop\|free_token_node\|noline\|on_token_node\|prefix\|ptype\|token_user_fields\|tree\)\>"
syn region propaneRegex start="/" end="/" skip="\v\\\\|\\/" syn region propaneRegex start="/" end="/" skip="\v\\\\|\\/"
hi def link propaneComment Comment hi def link propaneComment Comment
hi def link propaneKeyword Keyword hi def link propaneKeyword Keyword
hi def link propaneNameDecl Keyword
hi def link propaneRegex String hi def link propaneRegex String
hi def link propaneOperator Operator hi def link propaneOperator Operator
hi def link propaneFieldOperator Operator hi def link propaneFieldOperator Operator
+1 -1
View File
@@ -33,7 +33,7 @@ class Propane
def run(input_file, output_file, log_file, options) def run(input_file, output_file, log_file, options)
begin begin
grammar = Grammar.new(File.read(input_file), input_file) grammar = Grammar.new(File.read(input_file))
generator = Generator.new(grammar, output_file, log_file, options) generator = Generator.new(grammar, output_file, log_file, options)
generator.generate generator.generate
rescue Error => e rescue Error => e
+3 -40
View File
@@ -13,13 +13,8 @@ class Propane
@language = @language =
if output_file.end_with?(".d") if output_file.end_with?(".d")
"d" "d"
elsif output_file.end_with?(".c")
"c"
elsif output_file =~ %r{\.(cc|cpp|cxx)$}
@cpp = true
"c"
else else
raise Error.new("Could not determine target language from output file name (#{output_file})") "c"
end end
@options = options @options = options
process_grammar! process_grammar!
@@ -38,13 +33,7 @@ class Propane
output_file = @output_file output_file = @output_file
end end
erb = ERB.new(template, trim_mode: "<>") erb = ERB.new(template, trim_mode: "<>")
result = erb.result(binding.clone).lines.each_with_index.map do |line, i| result = erb.result(binding.clone)
if line == "#linereset\n"
%[#line #{i + 2} "#{output_file}"\n]
else
line
end
end.join
File.open(output_file, "wb") do |fh| File.open(output_file, "wb") do |fh|
fh.write(result) fh.write(result)
end end
@@ -276,24 +265,6 @@ class Propane
"context.user_terminate_code = (#{user_terminate_code}); return #{retval};" "context.user_terminate_code = (#{user_terminate_code}); return #{retval};"
end end
end end
code = code.gsub(/\$\{context\.(\w+)\}/) do |match|
fieldname = $1
case @language
when "c"
"context->#{fieldname}"
when "d"
"context.#{fieldname}"
end
end
code = code.gsub(/\$\{token\.(\w+)\}/) do |match|
fieldname = $1
case @language
when "c"
"token_tree_node->#{fieldname}"
when "d"
"token_tree_node.#{fieldname}"
end
end
if parser if parser
code = code.gsub(/\$\$/) do |match| code = code.gsub(/\$\$/) do |match|
case @language case @language
@@ -327,7 +298,7 @@ class Propane
end end
else else
code = code.gsub(/\$\$/) do |match| code = code.gsub(/\$\$/) do |match|
if @grammar.tree if @grammar.ast
case @language case @language
when "c" when "c"
"out_token_info->pvalue" "out_token_info->pvalue"
@@ -360,14 +331,6 @@ class Propane
code code
end end
# Get the lex function to use.
#
# @return [String]
# Lex function to use.
def lex_fn
@grammar.lex_fn || "#{@grammar.prefix}lex"
end
# Get the parser value type for the start rule. # Get the parser value type for the start rule.
# #
# @return [Array<String>] # @return [Array<String>]
+41 -114
View File
@@ -5,11 +5,9 @@ class Propane
# Reserve identifiers beginning with a double-underscore for internal use. # Reserve identifiers beginning with a double-underscore for internal use.
IDENTIFIER_REGEX = /(?:[a-zA-Z]|_[a-zA-Z0-9])[a-zA-Z_0-9]*/ IDENTIFIER_REGEX = /(?:[a-zA-Z]|_[a-zA-Z0-9])[a-zA-Z_0-9]*/
attr_reader :context_user_fields attr_reader :ast
attr_reader :lex_fn attr_reader :ast_prefix
attr_reader :tree attr_reader :ast_suffix
attr_reader :tree_prefix
attr_reader :tree_suffix
attr_reader :free_token_node attr_reader :free_token_node
attr_reader :modulename attr_reader :modulename
attr_reader :patterns attr_reader :patterns
@@ -19,11 +17,8 @@ class Propane
attr_reader :code_blocks attr_reader :code_blocks
attr_reader :ptypes attr_reader :ptypes
attr_reader :prefix attr_reader :prefix
attr_reader :on_token_node
attr_reader :token_user_fields
def initialize(input, filename) def initialize(input)
@filename = filename
@patterns = [] @patterns = []
@start_rules = [] @start_rules = []
@tokens = [] @tokens = []
@@ -35,13 +30,10 @@ class Propane
@input = input.gsub("\r\n", "\n") @input = input.gsub("\r\n", "\n")
@ptypes = {"default" => "void *"} @ptypes = {"default" => "void *"}
@prefix = "p_" @prefix = "p_"
@tree = false @ast = false
@tree_prefix = "" @ast_prefix = ""
@tree_suffix = "" @ast_suffix = ""
@free_token_node = "" @free_token_node = nil
@context_user_fields = nil
@on_token_node = ""
@token_user_fields = nil
parse_grammar! parse_grammar!
@start_rules << "Start" if @start_rules.empty? @start_rules << "Start" if @start_rules.empty?
end end
@@ -70,15 +62,11 @@ class Propane
if parse_white_space! if parse_white_space!
elsif parse_comment_line! elsif parse_comment_line!
elsif @modeline.nil? && parse_mode_label! elsif @modeline.nil? && parse_mode_label!
elsif parse_context_user_fields_statement! elsif parse_ast_statement!
elsif parse_lex_fn! elsif parse_ast_prefix_statement!
elsif parse_tree_statement! elsif parse_ast_suffix_statement!
elsif parse_tree_prefix_statement!
elsif parse_tree_suffix_statement!
elsif parse_free_token_node_statement! elsif parse_free_token_node_statement!
elsif parse_module_statement! elsif parse_module_statement!
elsif parse_on_token_node_statement!
elsif parse_token_user_fields_statement!
elsif parse_ptype_statement! elsif parse_ptype_statement!
elsif parse_pattern_statement! elsif parse_pattern_statement!
elsif parse_start_statement! elsif parse_start_statement!
@@ -88,7 +76,6 @@ class Propane
elsif parse_rule_statement! elsif parse_rule_statement!
elsif parse_code_block_statement! elsif parse_code_block_statement!
elsif parse_prefix_statement! elsif parse_prefix_statement!
elsif parse_noline_statement!
else else
if @input.size > 25 if @input.size > 25
@input = @input.slice(0..20) + "..." @input = @input.slice(0..20) + "..."
@@ -111,37 +98,27 @@ class Propane
consume!(/#.*\n/) consume!(/#.*\n/)
end end
def parse_context_user_fields_statement! def parse_ast_statement!
if md = consume!(/context_user_fields\b\s*/) if consume!(/ast\s*;/)
unless code = parse_code_block! @ast = true
raise Error.new("Line #{@line_number}: expected code block")
end
@context_user_fields ||= ""
@context_user_fields += code
end end
end end
def parse_lex_fn! def parse_ast_prefix_statement!
if md = consume!(/lex_fn\b\s*(\w+)\s*;/) if md = consume!(/ast_prefix\s+(\w+)\s*;/)
@lex_fn = md[1] @ast_prefix = md[1]
end end
end end
def parse_tree_statement! def parse_ast_suffix_statement!
if consume!(/tree\s*;/) if md = consume!(/ast_suffix\s+(\w+)\s*;/)
@tree = true @ast_suffix = md[1]
end end
end end
def parse_tree_prefix_statement! def parse_free_token_node_statement!
if md = consume!(/tree_prefix\s+(\w+)\s*;/) if md = consume!(/free_token_node\s+(\w+)\s*;/)
@tree_prefix = md[1] @free_token_node = md[1]
end
end
def parse_tree_suffix_statement!
if md = consume!(/tree_suffix\s+(\w+)\s*;/)
@tree_suffix = md[1]
end end
end end
@@ -155,40 +132,12 @@ class Propane
end end
end end
def parse_on_token_node_statement!
if md = consume!(/on_token_node\b\s*/)
unless code = parse_code_block!
raise Error.new("Line #{@line_number}: expected code block")
end
@on_token_node += code
end
end
def parse_token_user_fields_statement!
if md = consume!(/token_user_fields\b\s*/)
unless code = parse_code_block!
raise Error.new("Line #{@line_number}: expected code block")
end
@token_user_fields ||= ""
@token_user_fields += code
end
end
def parse_free_token_node_statement!
if md = consume!(/free_token_node\b\s*/)
unless code = parse_code_block!
raise Error.new("Line #{@line_number}: expected code block")
end
@free_token_node += code
end
end
def parse_ptype_statement! def parse_ptype_statement!
if consume!(/ptype\s+/) if consume!(/ptype\s+/)
name = "default" name = "default"
if md = consume!(/(#{IDENTIFIER_REGEX})\s*=\s*/) if md = consume!(/(#{IDENTIFIER_REGEX})\s*=\s*/)
if @tree if @ast
raise Error.new("Multiple ptypes are unsupported in tree mode") raise Error.new("Multiple ptypes are unsupported in AST mode")
end end
name = md[1] name = md[1]
end end
@@ -202,8 +151,8 @@ class Propane
md = consume!(/(#{IDENTIFIER_REGEX})\s*/, "expected token name") md = consume!(/(#{IDENTIFIER_REGEX})\s*/, "expected token name")
name = md[1] name = md[1]
if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/) if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/)
if @tree if @ast
raise Error.new("Multiple ptypes are unsupported in tree mode") raise Error.new("Multiple ptypes are unsupported in AST mode")
end end
ptypename = md[1] ptypename = md[1]
end end
@@ -226,8 +175,8 @@ class Propane
md = consume!(/(#{IDENTIFIER_REGEX})\s*/, "expected token name") md = consume!(/(#{IDENTIFIER_REGEX})\s*/, "expected token name")
name = md[1] name = md[1]
if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/) if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/)
if @tree if @ast
raise Error.new("Multiple ptypes are unsupported in tree mode") raise Error.new("Multiple ptypes are unsupported in AST mode")
end end
ptypename = md[1] ptypename = md[1]
end end
@@ -246,10 +195,8 @@ class Propane
raise Error.new("Line #{@line_number}: expected pattern to follow `drop'") raise Error.new("Line #{@line_number}: expected pattern to follow `drop'")
end end
consume!(/\s+/) consume!(/\s+/)
unless code = parse_code_block! consume!(/;/, "expected `;'")
consume!(/;/, "expected `;' or code block") @patterns << Pattern.new(pattern: pattern, line_number: @line_number, modes: get_modes_from_modeline)
end
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, code: code, modes: get_modes_from_modeline)
@modeline = nil @modeline = nil
true true
end end
@@ -258,12 +205,12 @@ class Propane
def parse_rule_statement! def parse_rule_statement!
if md = consume!(/(#{IDENTIFIER_REGEX})\s*(?:\((#{IDENTIFIER_REGEX})\))?\s*->\s*/) if md = consume!(/(#{IDENTIFIER_REGEX})\s*(?:\((#{IDENTIFIER_REGEX})\))?\s*->\s*/)
rule_name, ptypename = *md[1, 2] rule_name, ptypename = *md[1, 2]
if @tree && ptypename if @ast && ptypename
raise Error.new("Multiple ptypes are unsupported in tree mode") raise Error.new("Multiple ptypes are unsupported in AST mode")
end end
md = consume!(/((?:#{IDENTIFIER_REGEX}\??(?::#{IDENTIFIER_REGEX})?\s*)*)\s*/, "expected rule component list") md = consume!(/((?:#{IDENTIFIER_REGEX}\??(?::#{IDENTIFIER_REGEX})?\s*)*)\s*/, "expected rule component list")
components = md[1].strip.split(/\s+/) components = md[1].strip.split(/\s+/)
if @tree if @ast
consume!(/;/, "expected `;'") consume!(/;/, "expected `;'")
else else
unless code = parse_code_block! unless code = parse_code_block!
@@ -280,8 +227,8 @@ class Propane
if pattern = parse_pattern! if pattern = parse_pattern!
consume!(/\s+/) consume!(/\s+/)
if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/) if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/)
if @tree if @ast
raise Error.new("Multiple ptypes are unsupported in tree mode") raise Error.new("Multiple ptypes are unsupported in AST mode")
end end
ptypename = md[1] ptypename = md[1]
end end
@@ -306,14 +253,8 @@ class Propane
def parse_code_block_statement! def parse_code_block_statement!
if md = consume!(/<<([a-z]*)(.*?)>>\n/m) if md = consume!(/<<([a-z]*)(.*?)>>\n/m)
name, code = md[1..2] name, code = md[1..2]
code = code.chomp code.sub!(/\A\n/, "")
unless @noline code += "\n" unless code.end_with?("\n")
if code.start_with?("\n")
code = %[#line #{@line_number + 1} "#{@filename}"#{code}\n#linereset\n]
else
code = %[#line #{@line_number} "#{@filename}"\n#{code}\n#linereset\n]
end
end
if @code_blocks[name] if @code_blocks[name]
@code_blocks[name] += code @code_blocks[name] += code
else else
@@ -331,13 +272,6 @@ class Propane
end end
end end
def parse_noline_statement!
if md = consume!(/noline\s*;/)
@noline = true
true
end
end
def parse_pattern! def parse_pattern!
if md = consume!(%r{/}) if md = consume!(%r{/})
pattern = "" pattern = ""
@@ -351,8 +285,6 @@ class Propane
end end
elsif md = consume!(%r{(.)}) elsif md = consume!(%r{(.)})
pattern += md[1] pattern += md[1]
elsif @input == "" || @input.start_with?("\n")
raise Error.new("Line #{@line_number}: Unterminated pattern; expected `/`")
end end
end end
pattern pattern
@@ -361,14 +293,9 @@ class Propane
def parse_code_block! def parse_code_block!
if md = consume!(/<<(.*?)>>\n/m) if md = consume!(/<<(.*?)>>\n/m)
code = md[1].chomp code = md[1]
unless @noline code.sub!(/\A\n/, "")
if code.start_with?("\n") code += "\n" unless code.end_with?("\n")
code = %[#line #{@line_number + 1} "#{@filename}"#{code}\n#linereset\n]
else
code = %[#line #{@line_number} "#{@filename}"\n#{code}\n#linereset\n]
end
end
code code
end end
end end
+1 -1
View File
@@ -36,7 +36,7 @@ class Propane
# @return [Array<Integer>] # @return [Array<Integer>]
# Map this rule's components to their positions in the parent RuleSet's # Map this rule's components to their positions in the parent RuleSet's
# node field pointer array. This is used for tree construction. # node field pointer array. This is used for AST construction.
attr_accessor :rule_set_node_field_index_map attr_accessor :rule_set_node_field_index_map
# Construct a Rule. # Construct a Rule.
+23 -23
View File
@@ -4,8 +4,8 @@ class Propane
class RuleSet class RuleSet
# @return [Array<Hash>] # @return [Array<Hash>]
# tree fields. # AST fields.
attr_reader :tree_fields attr_reader :ast_fields
# @return [Integer] # @return [Integer]
# ID of the RuleSet. # ID of the RuleSet.
@@ -100,28 +100,28 @@ class Propane
# Finalize a RuleSet after adding all Rules to it. # Finalize a RuleSet after adding all Rules to it.
def finalize(grammar) def finalize(grammar)
if grammar.tree if grammar.ast
build_tree_fields(grammar) build_ast_fields(grammar)
end end
end end
private private
# Build the set of tree fields for this RuleSet. # Build the set of AST fields for this RuleSet.
# #
# This is an Array of Hashes. Each entry in the Array corresponds to a # This is an Array of Hashes. Each entry in the Array corresponds to a
# field location in the tree node. The entry is a Hash. It could have one or # field location in the AST node. The entry is a Hash. It could have one or
# two keys. It will always have the field name with a positional suffix as # two keys. It will always have the field name with a positional suffix as
# a key. It may also have the field name without the positional suffix if # a key. It may also have the field name without the positional suffix if
# that field only exists in one position across all Rules in the RuleSet. # that field only exists in one position across all Rules in the RuleSet.
# #
# @return [void] # @return [void]
def build_tree_fields(grammar) def build_ast_fields(grammar)
field_tree_node_indexes = {} field_ast_node_indexes = {}
field_indexes_across_all_rules = {} field_indexes_across_all_rules = {}
# Stores the index into @tree_fields by field alias name. # Stores the index into @ast_fields by field alias name.
field_aliases = {} field_aliases = {}
@tree_fields = [] @ast_fields = []
@rules.each do |rule| @rules.each do |rule|
rule.components.each_with_index do |component, i| rule.components.each_with_index do |component, i|
if component.is_a?(RuleSet) && component.optional? if component.is_a?(RuleSet) && component.optional?
@@ -132,25 +132,25 @@ class Propane
else else
node_name = component.name node_name = component.name
end end
struct_name = "#{grammar.tree_prefix}#{node_name}#{grammar.tree_suffix}" struct_name = "#{grammar.ast_prefix}#{node_name}#{grammar.ast_suffix}"
field_name = "p#{node_name}#{i + 1}" field_name = "p#{node_name}#{i + 1}"
unless field_tree_node_indexes[field_name] unless field_ast_node_indexes[field_name]
field_tree_node_indexes[field_name] = @tree_fields.size field_ast_node_indexes[field_name] = @ast_fields.size
@tree_fields << {field_name => struct_name} @ast_fields << {field_name => struct_name}
end end
rule.aliases.each do |alias_name, index| rule.aliases.each do |alias_name, index|
if index == i if index == i
alias_tree_fields_index = field_tree_node_indexes[field_name] alias_ast_fields_index = field_ast_node_indexes[field_name]
if field_aliases[alias_name] && field_aliases[alias_name] != alias_tree_fields_index if field_aliases[alias_name] && field_aliases[alias_name] != alias_ast_fields_index
raise Error.new("Error: conflicting tree node field positions for alias `#{alias_name}` in rule #{rule.name} defined on line #{rule.line_number}") raise Error.new("Error: conflicting AST node field positions for alias `#{alias_name}` in rule #{rule.name} defined on line #{rule.line_number}")
end end
field_aliases[alias_name] = alias_tree_fields_index field_aliases[alias_name] = alias_ast_fields_index
@tree_fields[alias_tree_fields_index][alias_name] = @tree_fields[alias_tree_fields_index].first[1] @ast_fields[alias_ast_fields_index][alias_name] = @ast_fields[alias_ast_fields_index].first[1]
end end
end end
field_indexes_across_all_rules[node_name] ||= Set.new field_indexes_across_all_rules[node_name] ||= Set.new
field_indexes_across_all_rules[node_name] << field_tree_node_indexes[field_name] field_indexes_across_all_rules[node_name] << field_ast_node_indexes[field_name]
rule.rule_set_node_field_index_map[i] = field_tree_node_indexes[field_name] rule.rule_set_node_field_index_map[i] = field_ast_node_indexes[field_name]
end end
end end
field_indexes_across_all_rules.each do |node_name, indexes_across_all_rules| field_indexes_across_all_rules.each do |node_name, indexes_across_all_rules|
@@ -158,8 +158,8 @@ class Propane
# If this field was only seen in one position across all rules, # If this field was only seen in one position across all rules,
# then add an alias to the positional field name that does not # then add an alias to the positional field name that does not
# include the position. # include the position.
@tree_fields[indexes_across_all_rules.first]["p#{node_name}"] = @ast_fields[indexes_across_all_rules.first]["p#{node_name}"] =
"#{grammar.tree_prefix}#{node_name}#{grammar.tree_suffix}" "#{grammar.ast_prefix}#{node_name}#{grammar.ast_suffix}"
end end
end end
end end
+1 -1
View File
@@ -1,3 +1,3 @@
class Propane class Propane
VERSION = "4.5.0" VERSION = "2.3.0"
end end
@@ -1,5 +1,5 @@
tree; ast;
tree_prefix P; ast_prefix P;
<<header <<header
#include <stdio.h> #include <stdio.h>
@@ -1,5 +1,5 @@
tree; ast;
tree_prefix P; ast_prefix P;
<< <<
import std.bigint; import std.bigint;
+9 -44
View File
@@ -28,7 +28,7 @@ B -> <<
b = 0; b = 0;
>> >>
EOF EOF
grammar = Grammar.new(input, "test.propane") grammar = Grammar.new(input)
expect(grammar.modulename).to eq "a.b" expect(grammar.modulename).to eq "a.b"
expect(grammar.ptype).to eq "XYZ *" expect(grammar.ptype).to eq "XYZ *"
expect(grammar.ptypes).to eq("default" => "XYZ *") expect(grammar.ptypes).to eq("default" => "XYZ *")
@@ -62,7 +62,7 @@ EOF
expect(o).to_not be_nil expect(o).to_not be_nil
expect(o.pattern).to eq "token_with_code" expect(o.pattern).to eq "token_with_code"
expect(o.line_number).to eq 11 expect(o.line_number).to eq 11
expect(o.code).to eq %[#line 12 "test.propane"\nCode for the token\n#linereset\n] expect(o.code).to eq "Code for the token\n"
o = grammar.tokens.find {|token| token.name == "token_with_no_pattern"} o = grammar.tokens.find {|token| token.name == "token_with_no_pattern"}
expect(o).to_not be_nil expect(o).to_not be_nil
@@ -83,7 +83,7 @@ EOF
expect(o.name).to eq "A" expect(o.name).to eq "A"
expect(o.components).to eq %w[B] expect(o.components).to eq %w[B]
expect(o.line_number).to eq 19 expect(o.line_number).to eq 19
expect(o.code).to eq %[#line 20 "test.propane"\n a = 42;\n#linereset\n] expect(o.code).to eq " a = 42;\n"
o = grammar.rules[1] o = grammar.rules[1]
expect(o.name).to eq "B" expect(o.name).to eq "B"
@@ -95,7 +95,7 @@ EOF
expect(o.name).to eq "B" expect(o.name).to eq "B"
expect(o.components).to eq [] expect(o.components).to eq []
expect(o.line_number).to eq 23 expect(o.line_number).to eq 23
expect(o.code).to eq %[#line 24 "test.propane"\n b = 0;\n#linereset\n] expect(o.code).to eq " b = 0;\n"
end end
it "parses code segments with semicolons" do it "parses code segments with semicolons" do
@@ -113,7 +113,7 @@ tokenid token_with_no_pattern;
prefix myparser_; prefix myparser_;
EOF EOF
grammar = Grammar.new(input, "test.propane") grammar = Grammar.new(input)
expect(grammar.prefix).to eq "myparser_" expect(grammar.prefix).to eq "myparser_"
o = grammar.tokens.find {|token| token.name == "code1"} o = grammar.tokens.find {|token| token.name == "code1"}
@@ -122,7 +122,7 @@ EOF
o = grammar.patterns.find {|pattern| pattern.token == o} o = grammar.patterns.find {|pattern| pattern.token == o}
expect(o).to_not be_nil expect(o).to_not be_nil
expect(o.code).to eq %[#line 2 "test.propane"\n a = b;\n return c;\n#linereset\n] expect(o.code).to eq " a = b;\n return c;\n"
o = grammar.tokens.find {|token| token.name == "code2"} o = grammar.tokens.find {|token| token.name == "code2"}
expect(o).to_not be_nil expect(o).to_not be_nil
@@ -130,42 +130,7 @@ EOF
o = grammar.patterns.find {|pattern| pattern.token == o} o = grammar.patterns.find {|pattern| pattern.token == o}
expect(o).to_not be_nil expect(o).to_not be_nil
expect(o.code).to eq %[#line 7 "test.propane"\n writeln("Hello there");\n#linereset\n] expect(o.code).to eq %[ writeln("Hello there");\n]
end
it "does not emit #line directives with noline statement" do
input = <<EOF
noline;
token code1 <<
a = b;
return c;
>>
token code2 <<
writeln("Hello there");
>>
tokenid token_with_no_pattern;
prefix myparser_;
EOF
grammar = Grammar.new(input, "test.propane")
expect(grammar.prefix).to eq "myparser_"
o = grammar.tokens.find {|token| token.name == "code1"}
expect(o).to_not be_nil
o = grammar.patterns.find {|pattern| pattern.token == o}
expect(o).to_not be_nil
expect(o.code).to eq %[\n a = b;\n return c;]
o = grammar.tokens.find {|token| token.name == "code2"}
expect(o).to_not be_nil
o = grammar.patterns.find {|pattern| pattern.token == o}
expect(o).to_not be_nil
expect(o.code).to eq %[\n writeln("Hello there");]
end end
it "supports mode labels" do it "supports mode labels" do
@@ -179,7 +144,7 @@ m2: /bar/ <<
drop /q/; drop /q/;
m3: drop /r/; m3: drop /r/;
EOF EOF
grammar = Grammar.new(input, "test.propane") grammar = Grammar.new(input)
o = grammar.tokens.find {|token| token.name == "a"} o = grammar.tokens.find {|token| token.name == "a"}
expect(o).to_not be_nil expect(o).to_not be_nil
@@ -232,7 +197,7 @@ tokenid int(integer);
Start (node) -> R; Start (node) -> R;
R -> abc int; R -> abc int;
EOF EOF
grammar = Grammar.new(input, "test.propane") grammar = Grammar.new(input)
o = grammar.tokens.find {|token| token.name == "abc"} o = grammar.tokens.find {|token| token.name == "abc"}
expect(o).to_not be_nil expect(o).to_not be_nil
+1 -1
View File
@@ -51,7 +51,7 @@ class TestLexer
end end
def run(grammar, input) def run(grammar, input)
grammar = Propane::Grammar.new(grammar, "test.propane") grammar = Propane::Grammar.new(grammar)
token_dfa = Propane::Lexer::DFA.new(grammar.patterns) token_dfa = Propane::Lexer::DFA.new(grammar.patterns)
test_lexer = TestLexer.new(token_dfa) test_lexer = TestLexer.new(token_dfa)
test_lexer.lex(input) test_lexer.lex(input)
+55 -359
View File
@@ -14,7 +14,6 @@ describe Propane do
end end
def run_propane(options = {}) def run_propane(options = {})
options[:language] ||= "d"
@statics[:build_test_id] ||= 0 @statics[:build_test_id] ||= 0
@statics[:build_test_id] += 1 @statics[:build_test_id] += 1
if ENV["dist_specs"] if ENV["dist_specs"]
@@ -95,15 +94,17 @@ EOF
File.binwrite("spec/run/.stdout", stdout) File.binwrite("spec/run/.stdout", stdout)
stderr.sub!(/^.*modules passed unittests\n/, "") stderr.sub!(/^.*modules passed unittests\n/, "")
results = Results.new(stdout, stderr, status) results = Results.new(stdout, stderr, status)
if %w[c cpp].include?(options[:language])
stdout, stderr, status = Open3.capture3("valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose spec/run/testparser") stdout, stderr, status = Open3.capture3("valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose spec/run/testparser")
vgout = stdout + stderr vgout = stdout + stderr
File.binwrite("spec/run/.vgout", vgout) File.binwrite("spec/run/.vgout", vgout)
vgout.scan(/(?:definitely|indirectly) lost: (\d+) bytes/) do |match| vgout.scan(/lost: (\d+) bytes/) do |match|
bytes = $1.to_i bytes = $1.to_i
if bytes > 0 if bytes > 0
raise "Valgrind detected memory leak" raise "Valgrind detected memory leak"
end end
end end
end
results results
end end
@@ -244,20 +245,20 @@ EOF
expect(results.status).to_not eq 0 expect(results.status).to_not eq 0
end end
it "errors when an alias is in different positions for different rules in a rule set when tree mode is enabled" do it "errors when an alias is in different positions for different rules in a rule set when AST mode is enabled" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
token a; token a;
token b; token b;
Start -> a:foo b; Start -> a:foo b;
Start -> b b:foo; Start -> b b:foo;
EOF EOF
results = run_propane(extra_args: %w[-w], capture: true) results = run_propane(extra_args: %w[-w], capture: true)
expect(results.stderr).to match %r{Error: conflicting tree node field positions for alias `foo`} expect(results.stderr).to match %r{Error: conflicting AST node field positions for alias `foo`}
expect(results.status).to_not eq 0 expect(results.status).to_not eq 0
end end
it "does not error when an alias is in different positions for different rules in a rule set when tree mode is not enabled" do it "does not error when an alias is in different positions for different rules in a rule set when AST mode is not enabled" do
write_grammar <<EOF write_grammar <<EOF
token a; token a;
token b; token b;
@@ -995,9 +996,9 @@ EOF
run_propane(language: language) run_propane(language: language)
end end
it "generates a tree" do it "generates an AST" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
ptype int; ptype int;
@@ -1031,17 +1032,17 @@ One -> one;
Two -> two; Two -> two;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree.#{language}", language: language) compile("spec/test_ast.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "supports tree node prefix and suffix" do it "supports AST node prefix and suffix" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
tree_prefix P ; ast_prefix P ;
tree_suffix S; ast_suffix S;
ptype int; ptype int;
@@ -1075,7 +1076,7 @@ One -> one;
Two -> two; Two -> two;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_ps.#{language}", language: language) compile("spec/test_ast_ps.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
@@ -1091,15 +1092,15 @@ EOF
compile("spec/test_start_rule.#{language}", language: language) compile("spec/test_start_rule.#{language}", language: language)
end end
it "allows specifying a different start rule with tree generation" do it "allows specifying a different start rule with AST generation" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
token hi; token hi;
start Top; start Top;
Top -> hi; Top -> hi;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_start_rule_tree.#{language}", language: language) compile("spec/test_start_rule_ast.#{language}", language: language)
end end
it "allows marking a rule component as optional" do it "allows marking a rule component as optional" do
@@ -1166,10 +1167,10 @@ EOF
]) ])
end end
it "allows marking a rule component as optional in tree generation mode" do it "allows marking a rule component as optional in AST generation mode" do
if language == "d" if language == "d"
write_grammar <<EOF write_grammar <<EOF
tree; ast;
<< <<
import std.stdio; import std.stdio;
@@ -1185,7 +1186,7 @@ R -> d c;
EOF EOF
else else
write_grammar <<EOF write_grammar <<EOF
tree; ast;
<< <<
#include <stdio.h> #include <stdio.h>
@@ -1201,16 +1202,16 @@ R -> d c;
EOF EOF
end end
run_propane(language: language) run_propane(language: language)
compile("spec/test_optional_rule_component_tree.#{language}", language: language) compile("spec/test_optional_rule_component_ast.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "allows naming an optional rule component in tree generation mode" do it "allows naming an optional rule component in AST generation mode" do
if language == "d" if language == "d"
write_grammar <<EOF write_grammar <<EOF
tree; ast;
<< <<
import std.stdio; import std.stdio;
@@ -1226,7 +1227,7 @@ R -> d c;
EOF EOF
else else
write_grammar <<EOF write_grammar <<EOF
tree; ast;
<< <<
#include <stdio.h> #include <stdio.h>
@@ -1242,15 +1243,15 @@ R -> d c;
EOF EOF
end end
run_propane(language: language) run_propane(language: language)
compile("spec/test_named_optional_rule_component_tree.#{language}", language: language) compile("spec/test_named_optional_rule_component_ast.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "stores token and rule positions in tree nodes" do it "stores token and rule positions in AST nodes" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
token a; token a;
token bb; token bb;
@@ -1262,7 +1263,7 @@ T -> bb;
T -> c; T -> c;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_token_positions.#{language}", language: language) compile("spec/test_ast_token_positions.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
@@ -1270,7 +1271,7 @@ EOF
it "stores invalid positions for empty rule matches" do it "stores invalid positions for empty rule matches" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
token a; token a;
token bb; token bb;
@@ -1282,15 +1283,15 @@ T -> a A;
A -> bb? c?; A -> bb? c?;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_invalid_positions.#{language}", language: language) compile("spec/test_ast_invalid_positions.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "allows specifying field aliases in tree mode" do it "allows specifying field aliases in AST mode" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
token a; token a;
token b; token b;
@@ -1302,15 +1303,15 @@ T -> b;
T -> c; T -> c;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_field_aliases.#{language}", language: language) compile("spec/test_ast_field_aliases.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "aliases the correct field when multiple rules are in a rule set in tree mode" do it "aliases the correct field when multiple rules are in a rule set in AST mode" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
token a; token a;
token b; token b;
@@ -1325,13 +1326,13 @@ T -> b;
T -> c; T -> c;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_field_aliases.#{language}", language: language) compile("spec/test_ast_field_aliases.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "allows specifying field aliases when tree mode is not enabled" do it "allows specifying field aliases when AST mode is not enabled" do
if language == "d" if language == "d"
write_grammar <<EOF write_grammar <<EOF
<< <<
@@ -1377,7 +1378,7 @@ EOF
expect(results.stdout).to match /first is foo1.*second is bar2/m expect(results.stdout).to match /first is foo1.*second is bar2/m
end end
it "aliases the correct field when multiple rules are in a rule set when tree mode is not enabled" do it "aliases the correct field when multiple rules are in a rule set when AST mode is not enabled" do
if language == "d" if language == "d"
write_grammar <<EOF write_grammar <<EOF
<< <<
@@ -1429,14 +1430,11 @@ EOF
expect(results.stdout).to match /first is foo1.*second is bar2/m expect(results.stdout).to match /first is foo1.*second is bar2/m
end end
# D garbage collector was freeing memory for nodes when it should not it "does not free memory allocated for AST nodes" do
# have been. This was due to pointers being in the TreeNode that was
# allocated by C malloc() function instead of allocated using D.
it "does not free memory allocated for tree nodes" do
ext = language == "cpp" ? "c" : language ext = language == "cpp" ? "c" : language
write_grammar(File.read("spec/tree_node_memory_remains.#{ext}.propane")) write_grammar(File.read("spec/ast_node_memory_remains.#{ext}.propane"))
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_node_memory_remains.#{language}", language: language) compile("spec/test_ast_node_memory_remains.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
@@ -1462,9 +1460,9 @@ EOF
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "allows multiple starting rules in tree mode" do it "allows multiple starting rules in AST mode" do
write_grammar <<EOF write_grammar <<EOF
tree; ast;
ptype int; ptype int;
token a << $$ = 1; >> token a << $$ = 1; >>
token b << $$ = 2; >> token b << $$ = 2; >>
@@ -1477,19 +1475,23 @@ Bs -> b:b Bs:bs;
start Start R Bs; start Start R Bs;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_starting_rules_tree.#{language}", language: language) compile("spec/test_starting_rules_ast.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
if %w[c cpp].include?(language) if %w[c cpp].include?(language)
it "allows a user function to free token node memory in tree mode" do it "allows a user function to free token node memory in AST mode" do
write_grammar <<EOF write_grammar <<EOF
tree; <<
free_token_node << static void free_token(Token * token)
free(${token.pvalue}); {
free(token->pvalue);
}
>> >>
ast;
free_token_node free_token;
ptype int *; ptype int *;
token a << token a <<
$$ = (int *)malloc(sizeof(int)); $$ = (int *)malloc(sizeof(int));
@@ -1502,314 +1504,7 @@ token b <<
Start -> a:a b:b; Start -> a:a b:b;
EOF EOF
run_propane(language: language) run_propane(language: language)
compile("spec/test_tree_delete_token_node_memory.#{language}", language: language) compile("spec/test_free_ast_token_node_memory.#{language}", language: language)
results = run_test(language: language)
expect(results.stderr).to eq ""
expect(results.status).to eq 0
end
end
it "executes code blocks associated with drop statements" do
if language == "d"
write_grammar <<EOF
<<
import std.stdio;
>>
drop /\\s+/;
drop /#(.*)\\n/ <<
stderr.write("comment: ", match);
>>
token a;
Start -> a;
EOF
else
write_grammar <<EOF
<<
#include <stdio.h>
#include <string.h>
>>
drop /\\s+/;
drop /#(.*)\\n/ <<
fprintf(stderr, "comment: %.*s", (int)match_length, match);
>>
token a;
Start -> a;
EOF
end
run_propane(language: language)
compile("spec/test_drop_code_block.#{language}", language: language)
results = run_test(language: language)
expect(results.stderr).to match %r{comment: # comment 1\n.*comment: # comment 2}m
expect(results.status).to eq 0
end
it "allows user-defined context fields" do
if language == "d"
write_grammar <<EOF
context_user_fields <<
string comments;
uint acount;
>>
drop /\\s+/;
drop /#(.*)\\n/ <<
${context.comments} ~= match;
>>
token a <<
${context.acount}++;
>>
Start -> As;
As -> ;
As -> a As;
EOF
else
write_grammar <<EOF
<<
#include <string.h>
#include <stdlib.h>
>>
context_user_fields <<
char * comments;
unsigned int acount;
>>
drop /\\s+/;
drop /#(.*)\\n/ <<
size_t cur_len = 0u;
if (${context.comments} != NULL)
cur_len = strlen(${context.comments});
char * commentsnew = (char *)malloc(cur_len + match_length + 1);
if (${context.comments} != NULL)
memcpy(commentsnew, ${context.comments}, cur_len);
memcpy(&commentsnew[cur_len], match, match_length);
commentsnew[cur_len + match_length] = '\\0';
if (${context.comments} != NULL)
{
free(${context.comments});
}
${context.comments} = commentsnew;
>>
token a <<
${context.acount}++;
>>
Start -> As;
As -> ;
As -> a As;
EOF
end
run_propane(language: language)
compile("spec/test_user_context_fields.#{language}", language: language)
results = run_test(language: language)
expect(results.stderr).to include %r{comments: # comment 1\n# comment 2}
expect(results.stderr).to include %r{acount: 11\n}
expect(results.status).to eq 0
end
it "allows custom token user fields" do
if language == "d"
write_grammar <<EOF
context_user_fields <<
string comments;
>>
token_user_fields <<
string comments;
>>
on_token_node <<
${token.comments} = ${context.comments};
${context.comments} = "";
>>
tree;
drop /\\s+/;
drop /#(.*)\\n/ <<
${context.comments} ~= match;
>>
token id /\\w+/;
Start -> IDs;
IDs -> ;
IDs -> id:id IDs;
EOF
elsif language == "c"
write_grammar <<EOF
<<
#include <string.h>
#include <stdlib.h>
>>
context_user_fields <<
char * comments;
>>
token_user_fields <<
char * comments;
>>
free_token_node <<
free(${token.comments});
>>
on_token_node <<
${token.comments} = ${context.comments};
${context.comments} = (char *)malloc(1);
${context.comments}[0] = '\\0';
>>
tree;
drop /\\s+/;
drop /#(.*)\\n/ <<
size_t cur_len = 0u;
if (${context.comments} != NULL)
cur_len = strlen(${context.comments});
char * commentsnew = (char *)malloc(cur_len + match_length + 1);
if (${context.comments} != NULL)
memcpy(commentsnew, ${context.comments}, cur_len);
memcpy(&commentsnew[cur_len], match, match_length);
commentsnew[cur_len + match_length] = '\\0';
if (${context.comments} != NULL)
{
free(${context.comments});
}
${context.comments} = commentsnew;
>>
token id /\\w+/;
Start -> IDs;
IDs -> ;
IDs -> id:id IDs;
EOF
else # C++
write_grammar <<EOF
<<header
#include <string>
>>
context_user_fields <<
std::string comments;
>>
token_user_fields <<
std::string comments;
>>
on_token_node <<
${token.comments} = ${context.comments};
${context.comments} = "";
>>
tree;
drop /\\s+/;
drop /#(.*)\\n/ <<
${context.comments} += std::string((const char *)match, match_length);
>>
token id /\\w+/;
Start -> IDs;
IDs -> ;
IDs -> id:id IDs;
EOF
end
run_propane(language: language)
compile("spec/test_token_user_fields.#{language}", language: language)
results = run_test(language: language)
expect(results.status).to eq 0
end
it "allows a custom lex function" do
if language == "d"
write_grammar <<EOF
<<
private size_t mylexfn(p_context_t * context, p_token_info_t * out_token_info)
{
static size_t count;
size_t result = P_SUCCESS;
if (count > 0)
{
out_token_info.token = TOKEN_a;
out_token_info.pvalue = p_value(count);
count--;
}
else
{
result = p_lex(context, out_token_info);
if (out_token_info.token == TOKEN_c)
{
count = 3;
}
}
return result;
}
>>
ptype size_t;
lex_fn mylexfn;
token a << $$ = 7; >>
token b << $$ = 8; >>
token c << $$ = 9; >>
Start -> << $$ = 0; >>
Start -> Start ID << $$ = ($1 << 4) | $2; >>
ID -> a << $$ = $1; >>
ID -> b << $$ = $1; >>
ID -> c << $$ = $1; >>
EOF
else
write_grammar <<EOF
<<
static size_t mylexfn(p_context_t * context, p_token_info_t * out_token_info)
{
static size_t count;
size_t result = P_SUCCESS;
if (count > 0)
{
out_token_info->token = TOKEN_a;
out_token_info->pvalue = p_value(count);
count--;
}
else
{
result = p_lex(context, out_token_info);
if (out_token_info->token == TOKEN_c)
{
count = 3;
}
}
return result;
}
>>
ptype size_t;
lex_fn mylexfn;
token a << $$ = 7; >>
token b << $$ = 8; >>
token c << $$ = 9; >>
Start -> << $$ = 0; >>
Start -> Start ID << $$ = ($1 << 4) | $2; >>
ID -> a << $$ = $1; >>
ID -> b << $$ = $1; >>
ID -> c << $$ = $1; >>
EOF
end
run_propane(language: language)
compile("spec/test_custom_lex_fn.#{language}", language: language)
results = run_test(language: language)
expect(results.status).to eq 0
end
it "provides accessor functions to extract user values from a parser value" do
if language == "d"
write_grammar <<EOF
ptype int;
ptype float = float;
ptype string = string;
drop /\\s+/;
token num /\\d+/ << $$ = 42; >>
token flt (float) /f/ << $$ = 1.5; >>
token str (string) /s/ << $$ = "hello"; >>
Start -> num flt str;
EOF
else
write_grammar <<EOF
ptype int;
ptype float = float;
ptype string = char *;
drop /\\s+/;
token num /\\d+/ << $$ = 42; >>
token flt (float) /f/ << $$ = 1.5; >>
token str (string) /s/ << $$ = (char *)"hello"; >>
Start -> num flt str;
EOF
end
run_propane(language: language)
compile("spec/test_value_accessors.#{language}", language: language)
results = run_test(language: language) results = run_test(language: language)
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
@@ -1817,3 +1512,4 @@ EOF
end end
end end
end end
end
+13 -16
View File
@@ -6,10 +6,10 @@
int main() int main()
{ {
char const * input = "a, ((b)), b"; char const * input = "a, ((b)), b";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
Start * start = p_result(context); Start * start = p_result(&context);
assert(start->pItems1 != NULL); assert(start->pItems1 != NULL);
assert(start->pItems != NULL); assert(start->pItems != NULL);
Items * items = start->pItems; Items * items = start->pItems;
@@ -33,22 +33,20 @@ int main()
assert_eq(22, itemsmore->pItem->pToken1->pvalue); assert_eq(22, itemsmore->pItem->pToken1->pvalue);
assert(itemsmore->pItemsMore == NULL); assert(itemsmore->pItemsMore == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = ""; input = "";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start->pItems == NULL); assert(start->pItems == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "2 1"; input = "2 1";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start->pItems != NULL); assert(start->pItems != NULL);
assert(start->pItems->pItem != NULL); assert(start->pItems->pItem != NULL);
assert(start->pItems->pItem->pDual != NULL); assert(start->pItems->pItem->pDual != NULL);
@@ -57,8 +55,7 @@ int main()
assert(start->pItems->pItem->pDual->pTwo2 == NULL); assert(start->pItems->pItem->pDual->pTwo2 == NULL);
assert(start->pItems->pItem->pDual->pOne1 == NULL); assert(start->pItems->pItem->pDual->pOne1 == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
return 0; return 0;
} }
+10 -15
View File
@@ -10,9 +10,10 @@ int main()
unittest unittest
{ {
string input = "a, ((b)), b"; string input = "a, ((b)), b";
p_context_t * context = p_context_new(input); p_context_t context;
assert_eq(P_SUCCESS, p_parse(context)); p_context_init(&context, input);
Start * start = p_result(context); assert_eq(P_SUCCESS, p_parse(&context));
Start * start = p_result(&context);
assert(start.pItems1 !is null); assert(start.pItems1 !is null);
assert(start.pItems !is null); assert(start.pItems !is null);
Items * items = start.pItems; Items * items = start.pItems;
@@ -36,20 +37,16 @@ unittest
assert_eq(22, itemsmore.pItem.pToken1.pvalue); assert_eq(22, itemsmore.pItem.pToken1.pvalue);
assert(itemsmore.pItemsMore is null); assert(itemsmore.pItemsMore is null);
p_tree_delete(start);
input = ""; input = "";
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start.pItems is null); assert(start.pItems is null);
p_tree_delete(start);
input = "2 1"; input = "2 1";
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start.pItems !is null); assert(start.pItems !is null);
assert(start.pItems.pItem !is null); assert(start.pItems.pItem !is null);
assert(start.pItems.pItem.pDual !is null); assert(start.pItems.pItem.pDual !is null);
@@ -57,6 +54,4 @@ unittest
assert(start.pItems.pItem.pDual.pOne2 !is null); assert(start.pItems.pItem.pDual.pOne2 !is null);
assert(start.pItems.pItem.pDual.pTwo2 is null); assert(start.pItems.pItem.pDual.pTwo2 is null);
assert(start.pItems.pItem.pDual.pOne1 is null); assert(start.pItems.pItem.pDual.pOne1 is null);
p_tree_delete(start);
} }
@@ -6,17 +6,16 @@
int main() int main()
{ {
char const * input = "\na\nb\nc"; char const * input = "\na\nb\nc";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(context); Start * start = p_result(&context);
assert_eq(TOKEN_a, start->first->pToken->token); assert_eq(TOKEN_a, start->first->pToken->token);
assert_eq(TOKEN_b, start->second->pToken->token); assert_eq(TOKEN_b, start->second->pToken->token);
assert_eq(TOKEN_c, start->third->pToken->token); assert_eq(TOKEN_c, start->third->pToken->token);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
return 0; return 0;
} }
@@ -10,13 +10,12 @@ int main()
unittest unittest
{ {
string input = "\na\nb\nc"; string input = "\na\nb\nc";
p_context_t * context = p_context_new(input); p_context_t context;
assert(p_parse(context) == P_SUCCESS); p_context_init(&context, input);
Start * start = p_result(context); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(&context);
assert_eq(TOKEN_a, start.first.pToken.token); assert_eq(TOKEN_a, start.first.pToken.token);
assert_eq(TOKEN_b, start.second.pToken.token); assert_eq(TOKEN_b, start.second.pToken.token);
assert_eq(TOKEN_c, start.third.pToken.token); assert_eq(TOKEN_c, start.third.pToken.token);
p_tree_delete(start);
} }
@@ -6,10 +6,10 @@
int main() int main()
{ {
char const * input = "\na\n bb ccc"; char const * input = "\na\n bb ccc";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(context); Start * start = p_result(&context);
assert_eq(2, start->pT1->pToken->position.row); assert_eq(2, start->pT1->pToken->position.row);
assert_eq(1, start->pT1->pToken->position.col); assert_eq(1, start->pT1->pToken->position.col);
@@ -30,13 +30,12 @@ int main()
assert_eq(3, start->end_position.row); assert_eq(3, start->end_position.row);
assert_eq(8, start->end_position.col); assert_eq(8, start->end_position.col);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "a\nbb"; input = "a\nbb";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(1, start->pT1->pToken->position.row); assert_eq(1, start->pT1->pToken->position.row);
assert_eq(1, start->pT1->pToken->position.col); assert_eq(1, start->pT1->pToken->position.col);
@@ -57,13 +56,12 @@ int main()
assert_eq(2, start->end_position.row); assert_eq(2, start->end_position.row);
assert_eq(2, start->end_position.col); assert_eq(2, start->end_position.col);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "a\nc\nc"; input = "a\nc\nc";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(1, start->pT1->pToken->position.row); assert_eq(1, start->pT1->pToken->position.row);
assert_eq(1, start->pT1->pToken->position.col); assert_eq(1, start->pT1->pToken->position.col);
@@ -84,13 +82,12 @@ int main()
assert_eq(3, start->end_position.row); assert_eq(3, start->end_position.row);
assert_eq(1, start->end_position.col); assert_eq(1, start->end_position.col);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "a"; input = "a";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(1, start->pT1->pToken->position.row); assert_eq(1, start->pT1->pToken->position.row);
assert_eq(1, start->pT1->pToken->position.col); assert_eq(1, start->pT1->pToken->position.col);
@@ -107,8 +104,7 @@ int main()
assert_eq(1, start->end_position.row); assert_eq(1, start->end_position.row);
assert_eq(1, start->end_position.col); assert_eq(1, start->end_position.col);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
return 0; return 0;
} }
@@ -10,9 +10,10 @@ int main()
unittest unittest
{ {
string input = "\na\n bb ccc"; string input = "\na\n bb ccc";
p_context_t * context = p_context_new(input); p_context_t context;
assert(p_parse(context) == P_SUCCESS); p_context_init(&context, input);
Start * start = p_result(context); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(&context);
assert_eq(2, start.pT1.pToken.position.row); assert_eq(2, start.pT1.pToken.position.row);
assert_eq(1, start.pT1.pToken.position.col); assert_eq(1, start.pT1.pToken.position.col);
@@ -33,12 +34,10 @@ unittest
assert_eq(3, start.end_position.row); assert_eq(3, start.end_position.row);
assert_eq(8, start.end_position.col); assert_eq(8, start.end_position.col);
p_tree_delete(start);
input = "a\nbb"; input = "a\nbb";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(1, start.pT1.pToken.position.row); assert_eq(1, start.pT1.pToken.position.row);
assert_eq(1, start.pT1.pToken.position.col); assert_eq(1, start.pT1.pToken.position.col);
@@ -59,12 +58,10 @@ unittest
assert_eq(2, start.end_position.row); assert_eq(2, start.end_position.row);
assert_eq(2, start.end_position.col); assert_eq(2, start.end_position.col);
p_tree_delete(start);
input = "a\nc\nc"; input = "a\nc\nc";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(1, start.pT1.pToken.position.row); assert_eq(1, start.pT1.pToken.position.row);
assert_eq(1, start.pT1.pToken.position.col); assert_eq(1, start.pT1.pToken.position.col);
@@ -85,12 +82,10 @@ unittest
assert_eq(3, start.end_position.row); assert_eq(3, start.end_position.row);
assert_eq(1, start.end_position.col); assert_eq(1, start.end_position.col);
p_tree_delete(start);
input = "a"; input = "a";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(1, start.pT1.pToken.position.row); assert_eq(1, start.pT1.pToken.position.row);
assert_eq(1, start.pT1.pToken.position.col); assert_eq(1, start.pT1.pToken.position.col);
@@ -106,6 +101,4 @@ unittest
assert_eq(1, start.position.col); assert_eq(1, start.position.col);
assert_eq(1, start.end_position.row); assert_eq(1, start.end_position.row);
assert_eq(1, start.end_position.col); assert_eq(1, start.end_position.col);
p_tree_delete(start);
} }
@@ -369,11 +369,11 @@ int main(int argc, char * argv[])
{"size_t_to_ulong", TOKEN_ulong}, {"size_t_to_ulong", TOKEN_ulong},
{"main", TOKEN_int}, {"main", TOKEN_int},
}; };
p_context_t * context; p_context_t context;
context = p_context_new((const uint8_t *)input, strlen(input)); p_context_init(&context, (const uint8_t *)input, strlen(input));
size_t result = p_parse(context); size_t result = p_parse(&context);
assert_eq(P_SUCCESS, result); assert_eq(P_SUCCESS, result);
PModule * pmod = p_result(context); PModule * pmod = p_result(&context);
PModuleItems * pmis = pmod->pModuleItems; PModuleItems * pmis = pmod->pModuleItems;
PFunctionDefinition ** pfds; PFunctionDefinition ** pfds;
size_t n_pfds = 0u; size_t n_pfds = 0u;
@@ -412,8 +412,7 @@ int main(int argc, char * argv[])
} }
free(pfds); free(pfds);
p_tree_delete(pmod); p_free_ast(pmod);
p_context_delete(context);
return 0; return 0;
} }
@@ -374,11 +374,11 @@ def main() -> int
Expected("size_t_to_ulong", TOKEN_ulong), Expected("size_t_to_ulong", TOKEN_ulong),
Expected("main", TOKEN_int), Expected("main", TOKEN_int),
]; ];
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
size_t result = p_parse(context); size_t result = p_parse(&context);
assert_eq(P_SUCCESS, result); assert_eq(P_SUCCESS, result);
PModule * pmod = p_result(context); PModule * pmod = p_result(&context);
PModuleItems * pmis = pmod.pModuleItems; PModuleItems * pmis = pmod.pModuleItems;
PFunctionDefinition *[] pfds; PFunctionDefinition *[] pfds;
while (pmis !is null) while (pmis !is null)
@@ -405,5 +405,4 @@ def main() -> int
stderr.writeln("Index ", i, ": expected ", expected[i].name, "/", expected[i].token, ", got ", pfds[i].name.pvalue.s, "/", pfds[i].returntype.pType.pTypeBase.pToken1.token); stderr.writeln("Index ", i, ": expected ", expected[i].name, "/", expected[i].token, ", got ", pfds[i].name.pvalue.s, "/", pfds[i].returntype.pType.pTypeBase.pToken1.token);
} }
} }
p_tree_delete(pmod);
} }
+13 -16
View File
@@ -6,10 +6,10 @@
int main() int main()
{ {
char const * input = "a, ((b)), b"; char const * input = "a, ((b)), b";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
PStartS * start = p_result(context); PStartS * start = p_result(&context);
assert(start->pItems1 != NULL); assert(start->pItems1 != NULL);
assert(start->pItems != NULL); assert(start->pItems != NULL);
PItemsS * items = start->pItems; PItemsS * items = start->pItems;
@@ -33,22 +33,20 @@ int main()
assert_eq(22, itemsmore->pItem->pToken1->pvalue); assert_eq(22, itemsmore->pItem->pToken1->pvalue);
assert(itemsmore->pItemsMore == NULL); assert(itemsmore->pItemsMore == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = ""; input = "";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start->pItems == NULL); assert(start->pItems == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "2 1"; input = "2 1";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start->pItems != NULL); assert(start->pItems != NULL);
assert(start->pItems->pItem != NULL); assert(start->pItems->pItem != NULL);
assert(start->pItems->pItem->pDual != NULL); assert(start->pItems->pItem->pDual != NULL);
@@ -57,8 +55,7 @@ int main()
assert(start->pItems->pItem->pDual->pTwo2 == NULL); assert(start->pItems->pItem->pDual->pTwo2 == NULL);
assert(start->pItems->pItem->pDual->pOne1 == NULL); assert(start->pItems->pItem->pDual->pOne1 == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
return 0; return 0;
} }
+10 -15
View File
@@ -10,9 +10,10 @@ int main()
unittest unittest
{ {
string input = "a, ((b)), b"; string input = "a, ((b)), b";
p_context_t * context = p_context_new(input); p_context_t context;
assert_eq(P_SUCCESS, p_parse(context)); p_context_init(&context, input);
PStartS * start = p_result(context); assert_eq(P_SUCCESS, p_parse(&context));
PStartS * start = p_result(&context);
assert(start.pItems1 !is null); assert(start.pItems1 !is null);
assert(start.pItems !is null); assert(start.pItems !is null);
PItemsS * items = start.pItems; PItemsS * items = start.pItems;
@@ -36,20 +37,16 @@ unittest
assert_eq(22, itemsmore.pItem.pToken1.pvalue); assert_eq(22, itemsmore.pItem.pToken1.pvalue);
assert(itemsmore.pItemsMore is null); assert(itemsmore.pItemsMore is null);
p_tree_delete(start);
input = ""; input = "";
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start.pItems is null); assert(start.pItems is null);
p_tree_delete(start);
input = "2 1"; input = "2 1";
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
start = p_result(context); start = p_result(&context);
assert(start.pItems !is null); assert(start.pItems !is null);
assert(start.pItems.pItem !is null); assert(start.pItems.pItem !is null);
assert(start.pItems.pItem.pDual !is null); assert(start.pItems.pItem.pDual !is null);
@@ -57,6 +54,4 @@ unittest
assert(start.pItems.pItem.pDual.pOne2 !is null); assert(start.pItems.pItem.pDual.pOne2 !is null);
assert(start.pItems.pItem.pDual.pTwo2 is null); assert(start.pItems.pItem.pDual.pTwo2 is null);
assert(start.pItems.pItem.pDual.pOne1 is null); assert(start.pItems.pItem.pDual.pOne1 is null);
p_tree_delete(start);
} }
@@ -6,10 +6,10 @@
int main() int main()
{ {
char const * input = "abbccc"; char const * input = "abbccc";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(context); Start * start = p_result(&context);
assert_eq(1, start->pT1->pToken->position.row); assert_eq(1, start->pT1->pToken->position.row);
assert_eq(1, start->pT1->pToken->position.col); assert_eq(1, start->pT1->pToken->position.col);
@@ -43,13 +43,12 @@ int main()
assert_eq(1, start->end_position.row); assert_eq(1, start->end_position.row);
assert_eq(6, start->end_position.col); assert_eq(6, start->end_position.col);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "\n\n bb\nc\ncc\n\n a"; input = "\n\n bb\nc\ncc\n\n a";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(3, start->pT1->pToken->position.row); assert_eq(3, start->pT1->pToken->position.row);
assert_eq(3, start->pT1->pToken->position.col); assert_eq(3, start->pT1->pToken->position.col);
@@ -83,8 +82,7 @@ int main()
assert_eq(7, start->end_position.row); assert_eq(7, start->end_position.row);
assert_eq(6, start->end_position.col); assert_eq(6, start->end_position.col);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
return 0; return 0;
} }
@@ -10,9 +10,10 @@ int main()
unittest unittest
{ {
string input = "abbccc"; string input = "abbccc";
p_context_t * context = p_context_new(input); p_context_t context;
assert(p_parse(context) == P_SUCCESS); p_context_init(&context, input);
Start * start = p_result(context); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(&context);
assert_eq(1, start.pT1.pToken.position.row); assert_eq(1, start.pT1.pToken.position.row);
assert_eq(1, start.pT1.pToken.position.col); assert_eq(1, start.pT1.pToken.position.col);
@@ -46,12 +47,10 @@ unittest
assert_eq(1, start.end_position.row); assert_eq(1, start.end_position.row);
assert_eq(6, start.end_position.col); assert_eq(6, start.end_position.col);
p_tree_delete(start);
input = "\n\n bb\nc\ncc\n\n a"; input = "\n\n bb\nc\ncc\n\n a";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert_eq(3, start.pT1.pToken.position.row); assert_eq(3, start.pT1.pToken.position.row);
assert_eq(3, start.pT1.pToken.position.col); assert_eq(3, start.pT1.pToken.position.col);
@@ -84,6 +83,4 @@ unittest
assert_eq(3, start.position.col); assert_eq(3, start.position.col);
assert_eq(7, start.end_position.row); assert_eq(7, start.end_position.row);
assert_eq(6, start.end_position.col); assert_eq(6, start.end_position.col);
p_tree_delete(start);
} }
+13 -17
View File
@@ -5,29 +5,25 @@
int main() int main()
{ {
char const * input = "1 + 2 * 3 + 4"; char const * input = "1 + 2 * 3 + 4";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(11, p_result(context)); assert_eq(11, p_result(&context));
p_context_delete(context);
input = "1 * 2 ** 4 * 3"; input = "1 * 2 ** 4 * 3";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(48, p_result(context)); assert_eq(48, p_result(&context));
p_context_delete(context);
input = "(1 + 2) * 3 + 4"; input = "(1 + 2) * 3 + 4";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(13, p_result(context)); assert_eq(13, p_result(&context));
p_context_delete(context);
input = "(2 * 2) ** 3 + 4 + 5"; input = "(2 * 2) ** 3 + 4 + 5";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(73, p_result(context)); assert_eq(73, p_result(&context));
p_context_delete(context);
return 0; return 0;
} }
+13 -13
View File
@@ -10,23 +10,23 @@ int main()
unittest unittest
{ {
string input = "1 + 2 * 3 + 4"; string input = "1 + 2 * 3 + 4";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(11, p_result(context)); assert_eq(11, p_result(&context));
input = "1 * 2 ** 4 * 3"; input = "1 * 2 ** 4 * 3";
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(48, p_result(context)); assert_eq(48, p_result(&context));
input = "(1 + 2) * 3 + 4"; input = "(1 + 2) * 3 + 4";
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(13, p_result(context)); assert_eq(13, p_result(&context));
input = "(2 * 2) ** 3 + 4 + 5"; input = "(2 * 2) ** 3 + 4 + 5";
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
assert_eq(73, p_result(context)); assert_eq(73, p_result(&context));
} }
-15
View File
@@ -1,15 +0,0 @@
#include "testparser.h"
#include "testutils.h"
#include <string.h>
int main()
{
char const * input = "cbacba";
p_context_t * context = p_context_new((uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context));
size_t result = p_result(context);
assert_eq(0x932187932187, result);
p_context_delete(context);
return 0;
}
-18
View File
@@ -1,18 +0,0 @@
import testparser;
import std.stdio;
import testutils;
int main()
{
return 0;
}
unittest
{
string input = "cbacba";
p_context_t * context = p_context_new(input);
assert_eq(P_SUCCESS, p_parse(context));
size_t result = p_result(context);
assert_eq(0x932187932187, result);
p_context_delete(context);
}
-15
View File
@@ -1,15 +0,0 @@
#include "testparser.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
int main()
{
char const * input = " # comment 1\n# comment 2\na\n";
p_context_t * context;
context = p_context_new((uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS);
p_context_delete(context);
return 0;
}
-16
View File
@@ -1,16 +0,0 @@
import testparser;
import std.stdio;
import testutils;
int main()
{
return 0;
}
unittest
{
string input = " # comment 1\n# comment 2\na\n";
p_context_t * context;
context = p_context_new(input);
assert(p_parse(context) == P_SUCCESS);
}
+21 -26
View File
@@ -5,43 +5,38 @@
int main() int main()
{ {
char const * input = "a 42"; char const * input = "a 42";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "a\n123\na a"; input = "a\n123\na a";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_UNEXPECTED_TOKEN); assert(p_parse(&context) == P_UNEXPECTED_TOKEN);
assert(p_position(context).row == 3); assert(p_position(&context).row == 3);
assert(p_position(context).col == 4); assert(p_position(&context).col == 4);
assert(p_token(context) == TOKEN_a); assert(p_token(&context) == TOKEN_a);
p_context_delete(context);
input = "12"; input = "12";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_UNEXPECTED_TOKEN); assert(p_parse(&context) == P_UNEXPECTED_TOKEN);
assert(p_position(context).row == 1); assert(p_position(&context).row == 1);
assert(p_position(context).col == 1); assert(p_position(&context).col == 1);
assert(p_token(context) == TOKEN_num); assert(p_token(&context) == TOKEN_num);
p_context_delete(context);
input = "a 12\n\nab"; input = "a 12\n\nab";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_UNEXPECTED_INPUT); assert(p_parse(&context) == P_UNEXPECTED_INPUT);
assert(p_position(context).row == 3); assert(p_position(&context).row == 3);
assert(p_position(context).col == 2); assert(p_position(&context).col == 2);
p_context_delete(context);
input = "a 12\n\na\n\n77\na \xAA"; input = "a 12\n\na\n\n77\na \xAA";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_DECODE_ERROR); assert(p_parse(&context) == P_DECODE_ERROR);
assert(p_position(context).row == 6); assert(p_position(&context).row == 6);
assert(p_position(context).col == 5); assert(p_position(&context).col == 5);
assert(strcmp(p_token_names[TOKEN_a], "a") == 0); assert(strcmp(p_token_names[TOKEN_a], "a") == 0);
assert(strcmp(p_token_names[TOKEN_num], "num") == 0); assert(strcmp(p_token_names[TOKEN_num], "num") == 0);
p_context_delete(context);
return 0; return 0;
} }
+17 -17
View File
@@ -9,31 +9,31 @@ int main()
unittest unittest
{ {
string input = "a 42"; string input = "a 42";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = "a\n123\na a"; input = "a\n123\na a";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_UNEXPECTED_TOKEN); assert(p_parse(&context) == P_UNEXPECTED_TOKEN);
assert(p_position(context) == p_position_t(3, 4)); assert(p_position(&context) == p_position_t(3, 4));
assert(p_token(context) == TOKEN_a); assert(p_token(&context) == TOKEN_a);
input = "12"; input = "12";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_UNEXPECTED_TOKEN); assert(p_parse(&context) == P_UNEXPECTED_TOKEN);
assert(p_position(context) == p_position_t(1, 1)); assert(p_position(&context) == p_position_t(1, 1));
assert(p_token(context) == TOKEN_num); assert(p_token(&context) == TOKEN_num);
input = "a 12\n\nab"; input = "a 12\n\nab";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_UNEXPECTED_INPUT); assert(p_parse(&context) == P_UNEXPECTED_INPUT);
assert(p_position(context) == p_position_t(3, 2)); assert(p_position(&context) == p_position_t(3, 2));
input = "a 12\n\na\n\n77\na \xAA"; input = "a 12\n\na\n\n77\na \xAA";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_DECODE_ERROR); assert(p_parse(&context) == P_DECODE_ERROR);
assert(p_position(context) == p_position_t(6, 5)); assert(p_position(&context) == p_position_t(6, 5));
assert(p_token_names[TOKEN_a] == "a"); assert(p_token_names[TOKEN_a] == "a");
assert(p_token_names[TOKEN_num] == "num"); assert(p_token_names[TOKEN_num] == "num");
+3 -4
View File
@@ -6,9 +6,8 @@
int main() int main()
{ {
char const * input = "foo1\nbar2"; char const * input = "foo1\nbar2";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
return 0; return 0;
} }
+3 -3
View File
@@ -9,7 +9,7 @@ int main()
unittest unittest
{ {
string input = "foo1\nbar2"; string input = "foo1\nbar2";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
} }
@@ -6,15 +6,14 @@
int main() int main()
{ {
char const * input = "ab"; char const * input = "ab";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
Start * start = p_result(context); Start * start = p_result(&context);
assert(start->a != NULL); assert(start->a != NULL);
assert(*start->a->pvalue == 1); assert(*start->a->pvalue == 1);
assert(start->b != NULL); assert(start->b != NULL);
assert(*start->b->pvalue == 2); assert(*start->b->pvalue == 2);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
} }
+12 -14
View File
@@ -38,75 +38,73 @@ int main()
p_token_info_t token_info; p_token_info_t token_info;
char const * input = "5 + 4 * \n677 + 567"; char const * input = "5 + 4 * \n677 + 567";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u); assert(token_info.position.row == 1u);
assert(token_info.position.col == 1u); assert(token_info.position.col == 1u);
assert(token_info.end_position.row == 1u); assert(token_info.end_position.row == 1u);
assert(token_info.end_position.col == 1u); assert(token_info.end_position.col == 1u);
assert(token_info.length == 1u); assert(token_info.length == 1u);
assert(token_info.token == TOKEN_int); assert(token_info.token == TOKEN_int);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u); assert(token_info.position.row == 1u);
assert(token_info.position.col == 3u); assert(token_info.position.col == 3u);
assert(token_info.end_position.row == 1u); assert(token_info.end_position.row == 1u);
assert(token_info.end_position.col == 3u); assert(token_info.end_position.col == 3u);
assert(token_info.length == 1u); assert(token_info.length == 1u);
assert(token_info.token == TOKEN_plus); assert(token_info.token == TOKEN_plus);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u); assert(token_info.position.row == 1u);
assert(token_info.position.col == 5u); assert(token_info.position.col == 5u);
assert(token_info.end_position.row == 1u); assert(token_info.end_position.row == 1u);
assert(token_info.end_position.col == 5u); assert(token_info.end_position.col == 5u);
assert(token_info.length == 1u); assert(token_info.length == 1u);
assert(token_info.token == TOKEN_int); assert(token_info.token == TOKEN_int);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u); assert(token_info.position.row == 1u);
assert(token_info.position.col == 7u); assert(token_info.position.col == 7u);
assert(token_info.end_position.row == 1u); assert(token_info.end_position.row == 1u);
assert(token_info.end_position.col == 7u); assert(token_info.end_position.col == 7u);
assert(token_info.length == 1u); assert(token_info.length == 1u);
assert(token_info.token == TOKEN_times); assert(token_info.token == TOKEN_times);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 2u); assert(token_info.position.row == 2u);
assert(token_info.position.col == 1u); assert(token_info.position.col == 1u);
assert(token_info.end_position.row == 2u); assert(token_info.end_position.row == 2u);
assert(token_info.end_position.col == 3u); assert(token_info.end_position.col == 3u);
assert(token_info.length == 3u); assert(token_info.length == 3u);
assert(token_info.token == TOKEN_int); assert(token_info.token == TOKEN_int);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 2u); assert(token_info.position.row == 2u);
assert(token_info.position.col == 5u); assert(token_info.position.col == 5u);
assert(token_info.end_position.row == 2u); assert(token_info.end_position.row == 2u);
assert(token_info.end_position.col == 5u); assert(token_info.end_position.col == 5u);
assert(token_info.length == 1u); assert(token_info.length == 1u);
assert(token_info.token == TOKEN_plus); assert(token_info.token == TOKEN_plus);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 2u); assert(token_info.position.row == 2u);
assert(token_info.position.col == 7u); assert(token_info.position.col == 7u);
assert(token_info.end_position.row == 2u); assert(token_info.end_position.row == 2u);
assert(token_info.end_position.col == 9u); assert(token_info.end_position.col == 9u);
assert(token_info.length == 3u); assert(token_info.length == 3u);
assert(token_info.token == TOKEN_int); assert(token_info.token == TOKEN_int);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 2u); assert(token_info.position.row == 2u);
assert(token_info.position.col == 10u); assert(token_info.position.col == 10u);
assert(token_info.end_position.row == 2u); assert(token_info.end_position.row == 2u);
assert(token_info.end_position.col == 10u); assert(token_info.end_position.col == 10u);
assert(token_info.length == 0u); assert(token_info.length == 0u);
assert(token_info.token == TOKEN___EOF); assert(token_info.token == TOKEN___EOF);
p_context_delete(context);
context = p_context_new((uint8_t const *)"", 0u); p_context_init(&context, (uint8_t const *)"", 0u);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info.position.row == 1u); assert(token_info.position.row == 1u);
assert(token_info.position.col == 1u); assert(token_info.position.col == 1u);
assert(token_info.end_position.row == 1u); assert(token_info.end_position.row == 1u);
assert(token_info.end_position.col == 1u); assert(token_info.end_position.col == 1u);
assert(token_info.length == 0u); assert(token_info.length == 0u);
assert(token_info.token == TOKEN___EOF); assert(token_info.token == TOKEN___EOF);
p_context_delete(context);
return 0; return 0;
} }
+12 -12
View File
@@ -44,26 +44,26 @@ unittest
{ {
p_token_info_t token_info; p_token_info_t token_info;
string input = "5 + 4 * \n677 + 567"; string input = "5 + 4 * \n677 + 567";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(1, 1), p_position_t(1, 1), 1, TOKEN_int)); assert(token_info == p_token_info_t(p_position_t(1, 1), p_position_t(1, 1), 1, TOKEN_int));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(1, 3), p_position_t(1, 3), 1, TOKEN_plus)); assert(token_info == p_token_info_t(p_position_t(1, 3), p_position_t(1, 3), 1, TOKEN_plus));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(1, 5), p_position_t(1, 5), 1, TOKEN_int)); assert(token_info == p_token_info_t(p_position_t(1, 5), p_position_t(1, 5), 1, TOKEN_int));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(1, 7), p_position_t(1, 7), 1, TOKEN_times)); assert(token_info == p_token_info_t(p_position_t(1, 7), p_position_t(1, 7), 1, TOKEN_times));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(2, 1), p_position_t(2, 3), 3, TOKEN_int)); assert(token_info == p_token_info_t(p_position_t(2, 1), p_position_t(2, 3), 3, TOKEN_int));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(2, 5), p_position_t(2, 5), 1, TOKEN_plus)); assert(token_info == p_token_info_t(p_position_t(2, 5), p_position_t(2, 5), 1, TOKEN_plus));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(2, 7), p_position_t(2, 9), 3, TOKEN_int)); assert(token_info == p_token_info_t(p_position_t(2, 7), p_position_t(2, 9), 3, TOKEN_int));
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(2, 10), p_position_t(2, 10), 0, TOKEN___EOF)); assert(token_info == p_token_info_t(p_position_t(2, 10), p_position_t(2, 10), 0, TOKEN___EOF));
context = p_context_new(""); p_context_init(&context, "");
assert(p_lex(context, &token_info) == P_SUCCESS); assert(p_lex(&context, &token_info) == P_SUCCESS);
assert(token_info == p_token_info_t(p_position_t(1, 1), p_position_t(1, 1), 0, TOKEN___EOF)); assert(token_info == p_token_info_t(p_position_t(1, 1), p_position_t(1, 1), 0, TOKEN___EOF));
} }
+3 -4
View File
@@ -6,11 +6,10 @@
int main() int main()
{ {
char const * input = "identifier_123"; char const * input = "identifier_123";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass1\n"); printf("pass1\n");
p_context_delete(context);
return 0; return 0;
} }
+3 -3
View File
@@ -9,8 +9,8 @@ int main()
unittest unittest
{ {
string input = `identifier_123`; string input = `identifier_123`;
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass1"); writeln("pass1");
} }
+5 -7
View File
@@ -6,17 +6,15 @@
int main() int main()
{ {
char const * input = "abc \"a string\" def"; char const * input = "abc \"a string\" def";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass1\n"); printf("pass1\n");
p_context_delete(context);
input = "abc \"abc def\" def"; input = "abc \"abc def\" def";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass2\n"); printf("pass2\n");
p_context_delete(context);
return 0; return 0;
} }
+5 -5
View File
@@ -9,13 +9,13 @@ int main()
unittest unittest
{ {
string input = `abc "a string" def`; string input = `abc "a string" def`;
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass1"); writeln("pass1");
input = `abc "abc def" def`; input = `abc "abc def" def`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass2"); writeln("pass2");
} }
+5 -7
View File
@@ -6,17 +6,15 @@
int main() int main()
{ {
char const * input = "abc.def"; char const * input = "abc.def";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass1\n"); printf("pass1\n");
p_context_delete(context);
input = "abc . abc"; input = "abc . abc";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass2\n"); printf("pass2\n");
p_context_delete(context);
return 0; return 0;
} }
+5 -5
View File
@@ -9,13 +9,13 @@ int main()
unittest unittest
{ {
string input = `abc.def`; string input = `abc.def`;
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass1"); writeln("pass1");
input = `abc . abc`; input = `abc . abc`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass2"); writeln("pass2");
} }
+7 -9
View File
@@ -5,17 +5,15 @@
int main() int main()
{ {
char const * input = "x"; char const * input = "x";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 1u); assert(p_result(&context) == 1u);
p_context_delete(context);
input = "fabulous"; input = "fabulous";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 8u); assert(p_result(&context) == 8u);
p_context_delete(context);
return 0; return 0;
} }
+7 -7
View File
@@ -9,13 +9,13 @@ int main()
unittest unittest
{ {
string input = `x`; string input = `x`;
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 1u); assert(p_result(&context) == 1u);
input = `fabulous`; input = `fabulous`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 8u); assert(p_result(&context) == 8u);
} }
+6 -8
View File
@@ -5,16 +5,14 @@
int main() int main()
{ {
char const * input = "x"; char const * input = "x";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_UNEXPECTED_INPUT); assert(p_parse(&context) == P_UNEXPECTED_INPUT);
p_context_delete(context);
input = "123"; input = "123";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 123u); assert(p_result(&context) == 123u);
p_context_delete(context);
return 0; return 0;
} }
+6 -6
View File
@@ -9,12 +9,12 @@ int main()
unittest unittest
{ {
string input = `x`; string input = `x`;
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_UNEXPECTED_INPUT); assert(p_parse(&context) == P_UNEXPECTED_INPUT);
input = `123`; input = `123`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 123u); assert(p_result(&context) == 123u);
} }
+3 -4
View File
@@ -5,10 +5,9 @@
int main() int main()
{ {
char const * input = "\a\b\t\n\v\f\rt"; char const * input = "\a\b\t\n\v\f\rt";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
return 0; return 0;
} }
+3 -3
View File
@@ -9,7 +9,7 @@ int main()
unittest unittest
{ {
string input = "\a\b\t\n\v\f\rt"; string input = "\a\b\t\n\v\f\rt";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
} }
+6 -8
View File
@@ -6,16 +6,14 @@
int main() int main()
{ {
char const * input1 = "a\n1"; char const * input1 = "a\n1";
myp1_context_t * context1; myp1_context_t context1;
context1 = myp1_context_new((uint8_t const *)input1, strlen(input1)); myp1_context_init(&context1, (uint8_t const *)input1, strlen(input1));
assert(myp1_parse(context1) == MYP1_SUCCESS); assert(myp1_parse(&context1) == MYP1_SUCCESS);
myp1_context_delete(context1);
char const * input2 = "bcb"; char const * input2 = "bcb";
myp2_context_t * context2; myp2_context_t context2;
context2 = myp2_context_new((uint8_t const *)input2, strlen(input2)); myp2_context_init(&context2, (uint8_t const *)input2, strlen(input2));
assert(myp2_parse(context2) == MYP2_SUCCESS); assert(myp2_parse(&context2) == MYP2_SUCCESS);
myp2_context_delete(context2);
return 0; return 0;
} }
+6 -6
View File
@@ -10,12 +10,12 @@ int main()
unittest unittest
{ {
string input1 = "a\n1"; string input1 = "a\n1";
myp1_context_t * context1; myp1_context_t context1;
context1 = myp1_context_new(input1); myp1_context_init(&context1, input1);
assert(myp1_parse(context1) == MYP1_SUCCESS); assert(myp1_parse(&context1) == MYP1_SUCCESS);
string input2 = "bcb"; string input2 = "bcb";
myp2_context_t * context2; myp2_context_t context2;
context2 = myp2_context_new(input2); myp2_context_init(&context2, input2);
assert(myp2_parse(context2) == MYP2_SUCCESS); assert(myp2_parse(&context2) == MYP2_SUCCESS);
} }
@@ -6,10 +6,10 @@
int main() int main()
{ {
char const * input = "b"; char const * input = "b";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(context); Start * start = p_result(&context);
assert(start->a == NULL); assert(start->a == NULL);
assert(start->pToken2 != NULL); assert(start->pToken2 != NULL);
assert_eq(TOKEN_b, start->pToken2->token); assert_eq(TOKEN_b, start->pToken2->token);
@@ -17,13 +17,12 @@ int main()
assert(start->pR == NULL); assert(start->pR == NULL);
assert(start->r == NULL); assert(start->r == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "abcd"; input = "abcd";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start->a != NULL); assert(start->a != NULL);
assert_eq(TOKEN_a, start->pToken1->token); assert_eq(TOKEN_a, start->pToken1->token);
assert(start->pToken2 != NULL); assert(start->pToken2 != NULL);
@@ -34,20 +33,18 @@ int main()
assert(start->pR == start->r); assert(start->pR == start->r);
assert_eq(TOKEN_c, start->pR->pToken1->token); assert_eq(TOKEN_c, start->pR->pToken1->token);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "bdc"; input = "bdc";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start->a == NULL); assert(start->a == NULL);
assert(start->pToken2 != NULL); assert(start->pToken2 != NULL);
assert(start->r != NULL); assert(start->r != NULL);
assert_eq(TOKEN_d, start->pR->pToken1->token); assert_eq(TOKEN_d, start->pR->pToken1->token);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
return 0; return 0;
} }
@@ -10,9 +10,10 @@ int main()
unittest unittest
{ {
string input = "b"; string input = "b";
p_context_t * context = p_context_new(input); p_context_t context;
assert(p_parse(context) == P_SUCCESS); p_context_init(&context, input);
Start * start = p_result(context); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(&context);
assert(start.pToken1 is null); assert(start.pToken1 is null);
assert(start.pToken2 !is null); assert(start.pToken2 !is null);
assert_eq(TOKEN_b, start.pToken2.token); assert_eq(TOKEN_b, start.pToken2.token);
@@ -20,12 +21,10 @@ unittest
assert(start.pR is null); assert(start.pR is null);
assert(start.r is null); assert(start.r is null);
p_tree_delete(start);
input = "abcd"; input = "abcd";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start.pToken1 != null); assert(start.pToken1 != null);
assert_eq(TOKEN_a, start.pToken1.token); assert_eq(TOKEN_a, start.pToken1.token);
assert(start.pToken2 != null); assert(start.pToken2 != null);
@@ -36,16 +35,12 @@ unittest
assert(start.pR == start.r); assert(start.pR == start.r);
assert_eq(TOKEN_c, start.pR.pToken1.token); assert_eq(TOKEN_c, start.pR.pToken1.token);
p_tree_delete(start);
input = "bdc"; input = "bdc";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start.pToken1 is null); assert(start.pToken1 is null);
assert(start.pToken2 !is null); assert(start.pToken2 !is null);
assert(start.pR !is null); assert(start.pR !is null);
assert_eq(TOKEN_d, start.pR.pToken1.token); assert_eq(TOKEN_d, start.pR.pToken1.token);
p_tree_delete(start);
} }
+7 -10
View File
@@ -5,20 +5,17 @@
int main() int main()
{ {
char const * input = "b"; char const * input = "b";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "abcd"; input = "abcd";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "abdc"; input = "abdc";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
return 0; return 0;
} }
+7 -7
View File
@@ -9,15 +9,15 @@ int main()
unittest unittest
{ {
string input = "b"; string input = "b";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = "abcd"; input = "abcd";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = "abdc"; input = "abdc";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
} }
@@ -6,23 +6,22 @@
int main() int main()
{ {
char const * input = "b"; char const * input = "b";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(context); Start * start = p_result(&context);
assert(start->pToken1 == NULL); assert(start->pToken1 == NULL);
assert(start->pToken2 != NULL); assert(start->pToken2 != NULL);
assert_eq(TOKEN_b, start->pToken2->token); assert_eq(TOKEN_b, start->pToken2->token);
assert(start->pR3 == NULL); assert(start->pR3 == NULL);
assert(start->pR == NULL); assert(start->pR == NULL);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "abcd"; input = "abcd";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start->pToken1 != NULL); assert(start->pToken1 != NULL);
assert_eq(TOKEN_a, start->pToken1->token); assert_eq(TOKEN_a, start->pToken1->token);
assert(start->pToken2 != NULL); assert(start->pToken2 != NULL);
@@ -31,20 +30,18 @@ int main()
assert(start->pR == start->pR3); assert(start->pR == start->pR3);
assert_eq(TOKEN_c, start->pR->pToken1->token); assert_eq(TOKEN_c, start->pR->pToken1->token);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
input = "bdc"; input = "bdc";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start->pToken1 == NULL); assert(start->pToken1 == NULL);
assert(start->pToken2 != NULL); assert(start->pToken2 != NULL);
assert(start->pR != NULL); assert(start->pR != NULL);
assert_eq(TOKEN_d, start->pR->pToken1->token); assert_eq(TOKEN_d, start->pR->pToken1->token);
p_tree_delete(start); p_free_ast(start);
p_context_delete(context);
return 0; return 0;
} }
@@ -10,21 +10,20 @@ int main()
unittest unittest
{ {
string input = "b"; string input = "b";
p_context_t * context = p_context_new(input); p_context_t context;
assert(p_parse(context) == P_SUCCESS); p_context_init(&context, input);
Start * start = p_result(context); assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(&context);
assert(start.pToken1 is null); assert(start.pToken1 is null);
assert(start.pToken2 !is null); assert(start.pToken2 !is null);
assert_eq(TOKEN_b, start.pToken2.token); assert_eq(TOKEN_b, start.pToken2.token);
assert(start.pR3 is null); assert(start.pR3 is null);
assert(start.pR is null); assert(start.pR is null);
p_tree_delete(start);
input = "abcd"; input = "abcd";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start.pToken1 != null); assert(start.pToken1 != null);
assert_eq(TOKEN_a, start.pToken1.token); assert_eq(TOKEN_a, start.pToken1.token);
assert(start.pToken2 != null); assert(start.pToken2 != null);
@@ -33,16 +32,12 @@ unittest
assert(start.pR == start.pR3); assert(start.pR == start.pR3);
assert_eq(TOKEN_c, start.pR.pToken1.token); assert_eq(TOKEN_c, start.pR.pToken1.token);
p_tree_delete(start);
input = "bdc"; input = "bdc";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
start = p_result(context); start = p_result(&context);
assert(start.pToken1 is null); assert(start.pToken1 is null);
assert(start.pToken2 !is null); assert(start.pToken2 !is null);
assert(start.pR !is null); assert(start.pR !is null);
assert_eq(TOKEN_d, start.pR.pToken1.token); assert_eq(TOKEN_d, start.pR.pToken1.token);
p_tree_delete(start);
} }
+5 -7
View File
@@ -5,15 +5,13 @@
int main() int main()
{ {
char const * input = "aba"; char const * input = "aba";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "abb"; input = "abb";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
return 0; return 0;
} }
+5 -5
View File
@@ -9,11 +9,11 @@ int main()
unittest unittest
{ {
string input = "aba"; string input = "aba";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = "abb"; input = "abb";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
} }
+10 -13
View File
@@ -5,23 +5,20 @@
int main() int main()
{ {
char const * input = "a"; char const * input = "a";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_UNEXPECTED_TOKEN); assert(p_parse(&context) == P_UNEXPECTED_TOKEN);
assert(p_position(context).row == 1); assert(p_position(&context).row == 1);
assert(p_position(context).col == 2); assert(p_position(&context).col == 2);
assert(context->token == TOKEN___EOF); assert(context.token == TOKEN___EOF);
p_context_delete(context);
input = "a b"; input = "a b";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "bb"; input = "bb";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
return 0; return 0;
} }
+8 -8
View File
@@ -9,17 +9,17 @@ int main()
unittest unittest
{ {
string input = "a"; string input = "a";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_UNEXPECTED_TOKEN); assert(p_parse(&context) == P_UNEXPECTED_TOKEN);
assert(p_position(context) == p_position_t(1, 2)); assert(p_position(&context) == p_position_t(1, 2));
assert(context.token == TOKEN___EOF); assert(context.token == TOKEN___EOF);
input = "a b"; input = "a b";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = "bb"; input = "bb";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
} }
+3 -4
View File
@@ -5,10 +5,9 @@
int main() int main()
{ {
char const * input = "ab"; char const * input = "ab";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
return 0; return 0;
} }
+3 -3
View File
@@ -9,7 +9,7 @@ int main()
unittest unittest
{ {
string input = "ab"; string input = "ab";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
} }
+23 -30
View File
@@ -6,58 +6,51 @@
int main() int main()
{ {
char const * input = ""; char const * input = "";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "{}"; input = "{}";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context)->id == JSON_OBJECT); assert(p_result(&context)->id == JSON_OBJECT);
p_context_delete(context);
input = "[]"; input = "[]";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context)->id == JSON_ARRAY); assert(p_result(&context)->id == JSON_ARRAY);
p_context_delete(context);
input = "-45.6"; input = "-45.6";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context)->id == JSON_NUMBER); assert(p_result(&context)->id == JSON_NUMBER);
assert(p_result(context)->number == -45.6); assert(p_result(&context)->number == -45.6);
p_context_delete(context);
input = "2E-2"; input = "2E-2";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context)->id == JSON_NUMBER); assert(p_result(&context)->id == JSON_NUMBER);
assert(p_result(context)->number == 0.02); assert(p_result(&context)->number == 0.02);
p_context_delete(context);
input = "{\"hi\":true}"; input = "{\"hi\":true}";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
JSONValue * o = p_result(context); JSONValue * o = p_result(&context);
assert(o->id == JSON_OBJECT); assert(o->id == JSON_OBJECT);
assert_eq(1, o->object.size); assert_eq(1, o->object.size);
assert(strcmp(o->object.entries[0].name, "hi") == 0); assert(strcmp(o->object.entries[0].name, "hi") == 0);
assert(o->object.entries[0].value->id == JSON_TRUE); assert(o->object.entries[0].value->id == JSON_TRUE);
p_context_delete(context);
input = "{\"ff\": false, \"nn\": null}"; input = "{\"ff\": false, \"nn\": null}";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
o = p_result(context); o = p_result(&context);
assert(o->id == JSON_OBJECT); assert(o->id == JSON_OBJECT);
assert_eq(2, o->object.size); assert_eq(2, o->object.size);
assert(strcmp(o->object.entries[0].name, "ff") == 0); assert(strcmp(o->object.entries[0].name, "ff") == 0);
assert(o->object.entries[0].value->id == JSON_FALSE); assert(o->object.entries[0].value->id == JSON_FALSE);
assert(strcmp(o->object.entries[1].name, "nn") == 0); assert(strcmp(o->object.entries[1].name, "nn") == 0);
assert(o->object.entries[1].value->id == JSON_NULL); assert(o->object.entries[1].value->id == JSON_NULL);
p_context_delete(context);
return 0; return 0;
} }
+25 -25
View File
@@ -10,45 +10,45 @@ int main()
unittest unittest
{ {
string input = ``; string input = ``;
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = `{}`; input = `{}`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(cast(JSONObject)p_result(context)); assert(cast(JSONObject)p_result(&context));
input = `[]`; input = `[]`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(cast(JSONArray)p_result(context)); assert(cast(JSONArray)p_result(&context));
input = `-45.6`; input = `-45.6`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(cast(JSONNumber)p_result(context)); assert(cast(JSONNumber)p_result(&context));
assert((cast(JSONNumber)p_result(context)).value == -45.6); assert((cast(JSONNumber)p_result(&context)).value == -45.6);
input = `2E-2`; input = `2E-2`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(cast(JSONNumber)p_result(context)); assert(cast(JSONNumber)p_result(&context));
assert((cast(JSONNumber)p_result(context)).value == 0.02); assert((cast(JSONNumber)p_result(&context)).value == 0.02);
input = `{"hi":true}`; input = `{"hi":true}`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(cast(JSONObject)p_result(context)); assert(cast(JSONObject)p_result(&context));
JSONObject o = cast(JSONObject)p_result(context); JSONObject o = cast(JSONObject)p_result(&context);
assert(o.value["hi"]); assert(o.value["hi"]);
assert(cast(JSONTrue)o.value["hi"]); assert(cast(JSONTrue)o.value["hi"]);
input = `{"ff": false, "nn": null}`; input = `{"ff": false, "nn": null}`;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(cast(JSONObject)p_result(context)); assert(cast(JSONObject)p_result(&context));
o = cast(JSONObject)p_result(context); o = cast(JSONObject)p_result(&context);
assert(o.value["ff"]); assert(o.value["ff"]);
assert(cast(JSONFalse)o.value["ff"]); assert(cast(JSONFalse)o.value["ff"]);
assert(o.value["nn"]); assert(o.value["nn"]);
+10 -13
View File
@@ -5,23 +5,20 @@
int main() int main()
{ {
char const * input = "a"; char const * input = "a";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 1u); assert(p_result(&context) == 1u);
p_context_delete(context);
input = ""; input = "";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 0u); assert(p_result(&context) == 0u);
p_context_delete(context);
input = "aaaaaaaaaaaaaaaa"; input = "aaaaaaaaaaaaaaaa";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 16u); assert(p_result(&context) == 16u);
p_context_delete(context);
return 0; return 0;
} }
+10 -10
View File
@@ -9,18 +9,18 @@ int main()
unittest unittest
{ {
string input = "a"; string input = "a";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 1u); assert(p_result(&context) == 1u);
input = ""; input = "";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 0u); assert(p_result(&context) == 0u);
input = "aaaaaaaaaaaaaaaa"; input = "aaaaaaaaaaaaaaaa";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
assert(p_result(context) == 16u); assert(p_result(&context) == 16u);
} }
+5 -7
View File
@@ -6,17 +6,15 @@
int main() int main()
{ {
char const * input = "abcdef"; char const * input = "abcdef";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass1\n"); printf("pass1\n");
p_context_delete(context);
input = "defabcdef"; input = "defabcdef";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass2\n"); printf("pass2\n");
p_context_delete(context);
return 0; return 0;
} }
+5 -5
View File
@@ -9,13 +9,13 @@ int main()
unittest unittest
{ {
string input = "abcdef"; string input = "abcdef";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass1"); writeln("pass1");
input = "defabcdef"; input = "defabcdef";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass2"); writeln("pass2");
} }
+3 -4
View File
@@ -5,10 +5,9 @@
int main() int main()
{ {
char const * input = "defghidef"; char const * input = "defghidef";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
return 0; return 0;
} }
+3 -3
View File
@@ -9,7 +9,7 @@ int main()
unittest unittest
{ {
string input = "defghidef"; string input = "defghidef";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
} }
+19
View File
@@ -0,0 +1,19 @@
#include "testparser.h"
#include <assert.h>
#include <string.h>
#include "testutils.h"
int main()
{
char const * input = "hi";
p_context_t context;
p_context_init(&context, (uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(&context));
Top * top = p_result(&context);
assert(top->pToken != NULL);
assert_eq(TOKEN_hi, top->pToken->token);
p_free_ast(top);
return 0;
}
@@ -10,10 +10,10 @@ int main()
unittest unittest
{ {
string input = "hi"; string input = "hi";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert_eq(P_SUCCESS, p_parse(context)); assert_eq(P_SUCCESS, p_parse(&context));
Top * top = p_result(context); Top * top = p_result(&context);
assert(top.pToken !is null); assert(top.pToken !is null);
assert_eq(TOKEN_hi, top.pToken.token); assert_eq(TOKEN_hi, top.pToken.token);
} }
-20
View File
@@ -1,20 +0,0 @@
#include "testparser.h"
#include <assert.h>
#include <string.h>
#include "testutils.h"
int main()
{
char const * input = "hi";
p_context_t * context;
context = p_context_new((uint8_t const *)input, strlen(input));
assert_eq(P_SUCCESS, p_parse(context));
Top * top = p_result(context);
assert(top->pToken != NULL);
assert_eq(TOKEN_hi, top->pToken->token);
p_tree_delete(top);
p_context_delete(context);
return 0;
}
+10 -13
View File
@@ -6,25 +6,22 @@
int main() int main()
{ {
char const * input = "bbbb"; char const * input = "bbbb";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
int result = p_result(context); int result = p_result(&context);
assert_eq(8, result); assert_eq(8, result);
p_context_delete(context);
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse_Bs(context) == P_SUCCESS); assert(p_parse_Bs(&context) == P_SUCCESS);
result = p_result_Bs(context); result = p_result_Bs(&context);
assert_eq(8, result); assert_eq(8, result);
p_context_delete(context);
input = "c"; input = "c";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse_R(context) == P_SUCCESS); assert(p_parse_R(&context) == P_SUCCESS);
result = p_result_R(context); result = p_result_R(&context);
assert_eq(3, result); assert_eq(3, result);
p_context_delete(context);
return 0; return 0;
} }
+10 -10
View File
@@ -10,20 +10,20 @@ int main()
unittest unittest
{ {
string input = "bbbb"; string input = "bbbb";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
int result = p_result(context); int result = p_result(&context);
assert(result == 8); assert(result == 8);
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse_Bs(context) == P_SUCCESS); assert(p_parse_Bs(&context) == P_SUCCESS);
result = p_result_Bs(context); result = p_result_Bs(&context);
assert(result == 8); assert(result == 8);
input = "c"; input = "c";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse_R(context) == P_SUCCESS); assert(p_parse_R(&context) == P_SUCCESS);
result = p_result_R(context); result = p_result_R(&context);
assert(result == 3); assert(result == 3);
} }
+37
View File
@@ -0,0 +1,37 @@
#include "testparser.h"
#include <assert.h>
#include <string.h>
#include "testutils.h"
int main()
{
char const * input = "bbbb";
p_context_t context;
p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(&context);
assert_not_null(start->bs);
assert_not_null(start->bs->b);
assert_not_null(start->bs->bs->b);
assert_not_null(start->bs->bs->bs->b);
assert_not_null(start->bs->bs->bs->bs->b);
p_free_ast(start);
p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse_Bs(&context) == P_SUCCESS);
Bs * bs = p_result_Bs(&context);
assert_not_null(bs->b);
assert_not_null(bs->bs->b);
assert_not_null(bs->bs->bs->b);
assert_not_null(bs->bs->bs->bs->b);
p_free_ast_Bs(bs);
input = "c";
p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse_R(&context) == P_SUCCESS);
R * r = p_result_R(&context);
assert_not_null(r->c);
p_free_ast_R(r);
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
import testparser;
import std.stdio;
import testutils;
int main()
{
return 0;
}
unittest
{
string input = "bbbb";
p_context_t context;
p_context_init(&context, input);
assert(p_parse(&context) == P_SUCCESS);
Start * start = p_result(&context);
assert(start.bs);
assert(start.bs.b);
assert(start.bs.bs.b);
assert(start.bs.bs.bs.b);
assert(start.bs.bs.bs.bs.b);
p_context_init(&context, input);
assert(p_parse_Bs(&context) == P_SUCCESS);
Bs * bs = p_result_Bs(&context);
assert(bs.b);
assert(bs.bs.b);
assert(bs.bs.bs.b);
assert(bs.bs.bs.bs.b);
input = "c";
p_context_init(&context, input);
assert(p_parse_R(&context) == P_SUCCESS);
R * r = p_result_R(&context);
assert(r.c);
}
-40
View File
@@ -1,40 +0,0 @@
#include "testparser.h"
#include <assert.h>
#include <string.h>
#include "testutils.h"
int main()
{
char const * input = "bbbb";
p_context_t * context;
context = p_context_new((uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS);
Start * start = p_result(context);
assert_not_null(start->bs);
assert_not_null(start->bs->b);
assert_not_null(start->bs->bs->b);
assert_not_null(start->bs->bs->bs->b);
assert_not_null(start->bs->bs->bs->bs->b);
p_tree_delete(start);
p_context_delete(context);
context = p_context_new((uint8_t const *)input, strlen(input));
assert(p_parse_Bs(context) == P_SUCCESS);
Bs * bs = p_result_Bs(context);
assert_not_null(bs->b);
assert_not_null(bs->bs->b);
assert_not_null(bs->bs->bs->b);
assert_not_null(bs->bs->bs->bs->b);
p_tree_delete_Bs(bs);
p_context_delete(context);
input = "c";
context = p_context_new((uint8_t const *)input, strlen(input));
assert(p_parse_R(context) == P_SUCCESS);
R * r = p_result_R(context);
assert_not_null(r->c);
p_tree_delete_R(r);
p_context_delete(context);
return 0;
}
-41
View File
@@ -1,41 +0,0 @@
import testparser;
import std.stdio;
import testutils;
int main()
{
return 0;
}
unittest
{
string input = "bbbb";
p_context_t * context = p_context_new(input);
assert(p_parse(context) == P_SUCCESS);
Start * start = p_result(context);
assert(start.bs);
assert(start.bs.b);
assert(start.bs.bs.b);
assert(start.bs.bs.bs.b);
assert(start.bs.bs.bs.bs.b);
p_tree_delete(start);
context = p_context_new(input);
assert(p_parse_Bs(context) == P_SUCCESS);
Bs * bs = p_result_Bs(context);
assert(bs.b);
assert(bs.bs.b);
assert(bs.bs.bs.b);
assert(bs.bs.bs.bs.b);
p_tree_delete_Bs(bs);
input = "c";
context = p_context_new(input);
assert(p_parse_R(context) == P_SUCCESS);
R * r = p_result_R(context);
assert(r.c);
p_tree_delete_R(r);
}
-46
View File
@@ -1,46 +0,0 @@
#include "testparser.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char const * input =
"# c1\n"
"# c2\n"
"\n"
"first\n"
"\n \n \n"
" # s1\n"
" # s2\n"
"second\n";
p_context_t * context;
context = p_context_new((uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS);
Start * start = p_result(context);
assert(start->pIDs);
assert(start->pIDs->id);
#ifdef __cplusplus
assert(start->pIDs->id->comments == "# c1\n# c2\n");
#else
assert(start->pIDs->id->comments);
assert(strcmp(start->pIDs->id->comments, "# c1\n# c2\n") == 0);
#endif
assert(start->pIDs->pIDs);
assert(start->pIDs->pIDs->id);
#ifdef __cplusplus
assert(start->pIDs->pIDs->id->comments == "# s1\n# s2\n");
#else
assert(start->pIDs->pIDs->id->comments);
assert(strcmp(start->pIDs->pIDs->id->comments, "# s1\n# s2\n") == 0);
#endif
#ifndef __cplusplus
free(context->comments);
#endif
p_context_delete(context);
p_tree_delete(start);
return 0;
}
-31
View File
@@ -1,31 +0,0 @@
import testparser;
import std.stdio;
int main()
{
return 0;
}
unittest
{
string input =
"# c1\n" ~
"# c2\n" ~
"\n" ~
"first\n" ~
"\n \n \n" ~
" # s1\n" ~
" # s2\n" ~
"second\n";
p_context_t * context = p_context_new(input);
assert(p_parse(context) == P_SUCCESS);
Start * start = p_result(context);
assert(start.pIDs);
assert(start.pIDs.id);
assert(start.pIDs.id.comments == "# c1\n# c2\n");
assert(start.pIDs.pIDs);
assert(start.pIDs.pIDs.id);
assert(start.pIDs.pIDs.id.comments == "# s1\n# s2\n");
p_tree_delete(start);
}
+5 -7
View File
@@ -6,17 +6,15 @@
int main() int main()
{ {
char const * input = "abcdef"; char const * input = "abcdef";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass1\n"); printf("pass1\n");
p_context_delete(context);
input = "abcabcdef"; input = "abcabcdef";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
printf("pass2\n"); printf("pass2\n");
p_context_delete(context);
return 0; return 0;
} }
+5 -5
View File
@@ -9,13 +9,13 @@ int main()
unittest unittest
{ {
string input = "abcdef"; string input = "abcdef";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass1"); writeln("pass1");
input = "abcabcdef"; input = "abcabcdef";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
writeln("pass2"); writeln("pass2");
} }
-20
View File
@@ -1,20 +0,0 @@
#include "testparser.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char const * input = "aaa\n\n\na\n # comment 1\na a aa\n\naa\n# comment 2\na\n";
p_context_t * context;
context = p_context_new((uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS);
fprintf(stderr, "comments: %s", context->comments);
fprintf(stderr, "acount: %u\n", context->acount);
free(context->comments);
p_context_delete(context);
return 0;
}
-19
View File
@@ -1,19 +0,0 @@
import testparser;
import std.stdio;
import testutils;
int main()
{
return 0;
}
unittest
{
string input = "aaa\n\n\na\n # comment 1\na a aa\n\naa\n# comment 2\na\n";
p_context_t * context;
context = p_context_new(input);
assert(p_parse(context) == P_SUCCESS);
stderr.writeln("comments: ", context.comments);
stderr.writeln("acount: ", context.acount);
}
+6 -8
View File
@@ -6,16 +6,14 @@
int main() int main()
{ {
char const * input = "aacc"; char const * input = "aacc";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "abc"; input = "abc";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_USER_TERMINATED); assert(p_parse(&context) == P_USER_TERMINATED);
assert(p_user_terminate_code(context) == 4200); assert(p_user_terminate_code(&context) == 4200);
p_context_delete(context);
return 0; return 0;
} }
+6 -6
View File
@@ -9,12 +9,12 @@ int main()
unittest unittest
{ {
string input = "aacc"; string input = "aacc";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = "abc"; input = "abc";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_USER_TERMINATED); assert(p_parse(&context) == P_USER_TERMINATED);
assert(p_user_terminate_code(context) == 4200); assert(p_user_terminate_code(&context) == 4200);
} }
+6 -8
View File
@@ -6,16 +6,14 @@
int main() int main()
{ {
char const * input = "a"; char const * input = "a";
p_context_t * context; p_context_t context;
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
p_context_delete(context);
input = "b"; input = "b";
context = p_context_new((uint8_t const *)input, strlen(input)); p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(context) == P_USER_TERMINATED); assert(p_parse(&context) == P_USER_TERMINATED);
assert(p_user_terminate_code(context) == 8675309); assert(p_user_terminate_code(&context) == 8675309);
p_context_delete(context);
return 0; return 0;
} }
+6 -6
View File
@@ -9,12 +9,12 @@ int main()
unittest unittest
{ {
string input = "a"; string input = "a";
p_context_t * context; p_context_t context;
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_SUCCESS); assert(p_parse(&context) == P_SUCCESS);
input = "b"; input = "b";
context = p_context_new(input); p_context_init(&context, input);
assert(p_parse(context) == P_USER_TERMINATED); assert(p_parse(&context) == P_USER_TERMINATED);
assert(p_user_terminate_code(context) == 8675309); assert(p_user_terminate_code(&context) == 8675309);
} }
-29
View File
@@ -1,29 +0,0 @@
#include "testparser.h"
#include <assert.h>
#include <string.h>
int main()
{
p_token_info_t token_info;
char const * input = "42 f s";
p_context_t * context;
context = p_context_new((uint8_t const *)input, strlen(input));
/* Default ptype value extracted with p_value_get(). */
assert(p_lex(context, &token_info) == P_SUCCESS);
assert(token_info.token == TOKEN_num);
assert(p_value_get(&token_info.pvalue) == 42);
/* Named ptype values extracted with p_value_get_XXX(). */
assert(p_lex(context, &token_info) == P_SUCCESS);
assert(token_info.token == TOKEN_flt);
assert(p_value_get_float(&token_info.pvalue) == 1.5);
assert(p_lex(context, &token_info) == P_SUCCESS);
assert(token_info.token == TOKEN_str);
assert(strcmp(p_value_get_string(&token_info.pvalue), "hello") == 0);
p_context_delete(context);
return 0;
}
Loaded 100 of 101 files, more files were not shown because too many files have changed in this diff. Show more