Skip to content

Commit 52e9eef

Browse files
committed
Replaceable jl_parse as single parser entry point
`jl_parse` calls a C function pointer which can be replaced with jl_set_parser(). This should make it possible to replace the flisp parser with julia code. Currently `jl_parse` takes Strings rather than C buffers to make it more natural to implement in Julia code. TODO: Could revisit this to decide whether it's desirable to require a `String` or whether we should have non-copying `unsafe_wrap` and `IOBuffer` for parsing.
1 parent d411c4e commit 52e9eef

File tree

8 files changed

+134
-71
lines changed

8 files changed

+134
-71
lines changed

base/client.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,9 @@ function eval_user_input(errio, @nospecialize(ast), show_value::Bool)
153153
end
154154

155155
function _parse_input_line_core(s::String, filename::String)
156-
ex = ccall(:jl_parse_all, Any, (Ptr{UInt8}, Csize_t, Ptr{UInt8}, Csize_t),
157-
s, sizeof(s), filename, sizeof(filename))
156+
JL_PARSE_TOPLEVEL = 3
157+
ex,_ = ccall(:jl_parse, Any, (Any, Any, Cint, Cint),
158+
s, filename, 1, JL_PARSE_TOPLEVEL)
158159
if ex isa Expr && ex.head === :toplevel
159160
if isempty(ex.args)
160161
return nothing

base/meta.jl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,20 @@ julia> Meta.parse("x = 3, y = 5", 5)
172172
function parse(str::AbstractString, pos::Integer; greedy::Bool=true, raise::Bool=true,
173173
depwarn::Bool=true)
174174
# pos is one based byte offset.
175-
# returns (expr, end_pos). expr is () in case of parse error.
176-
bstr = String(str)
175+
filename = "none"
176+
JL_PARSE_ATOM = 1
177+
JL_PARSE_STATEMENT = 2
178+
rule = greedy ? JL_PARSE_STATEMENT : JL_PARSE_ATOM
177179
# For now, assume all parser warnings are depwarns
180+
# TODO: remove parser-depwarn; parser no longer emits warnings.
178181
ex, pos = with_logger(depwarn ? current_logger() : NullLogger()) do
179-
ccall(:jl_parse_string, Any,
180-
(Ptr{UInt8}, Csize_t, Int32, Int32),
181-
bstr, sizeof(bstr), pos-1, greedy ? 1 : 0)
182+
ccall(:jl_parse, Any, (String, String, Cint, Cint),
183+
str, filename, pos, rule)
182184
end
183185
if raise && isa(ex,Expr) && ex.head === :error
184186
throw(ParseError(ex.args[1]))
185187
end
186-
return ex, pos+1 # C is zero-based, Julia is 1-based
188+
return ex, pos
187189
end
188190

189191
"""

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ endif
4242
RUNTIME_SRCS := \
4343
jltypes gf typemap ast builtins module interpreter symbol \
4444
dlload sys init task array dump staticdata toplevel jl_uv datatype \
45-
simplevector runtime_intrinsics precompile \
45+
simplevector runtime_intrinsics precompile frontend \
4646
threading partr stackwalk gc gc-debug gc-pages gc-stacks method \
4747
jlapi signal-handling safepoint timing subtype \
4848
crc32c APInt-C processor

src/ast.c

Lines changed: 37 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ extern "C" {
2727
#pragma warning(disable:4335)
2828
#endif
2929

30+
// TODO: Move non-flisp stuff into frontend.c (symbol init + macro expansion etc)
31+
3032
// head symbols for each expression type
3133
jl_sym_t *call_sym; jl_sym_t *invoke_sym;
3234
jl_sym_t *empty_sym; jl_sym_t *top_sym;
@@ -777,87 +779,61 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v)
777779
return julia_to_scm_noalloc2(fl_ctx, v);
778780
}
779781

780-
typedef enum {
781-
JL_PARSE_ATOM = 1,
782-
JL_PARSE_STATEMENTS = 2,
783-
JL_PARSE_TOPLEVEL = 3,
784-
} jl_parse_rule_t;
785-
786-
// Parse string `content` starting at byte offset `start_pos` attributing it to
787-
// `filename`. Return an svec of (parse_result, final_pos)
788-
JL_DLLEXPORT jl_value_t *jl_fl_parse(const char *content, size_t content_len,
789-
const char *filename, size_t filename_len,
790-
int start_pos, jl_parse_rule_t rule)
782+
// Parse string `content` starting at 1-based index `start_pos` attributing the
783+
// content to `filename`. Return an svec of (parse_result, final_pos)
784+
JL_DLLEXPORT jl_value_t *jl_fl_parse(jl_value_t *text, jl_value_t *filename,
785+
int start_pos, int rule)
791786
{
792787
JL_TIMING(PARSING);
793-
if (start_pos < 0 || start_pos > content_len) {
794-
jl_array_t *buf = jl_pchar_to_array(content, content_len);
795-
JL_GC_PUSH1(&buf);
788+
if (!jl_is_string(text) || !jl_is_string(filename)) {
789+
jl_errorf("File content and name must be Strings");
790+
}
791+
if (start_pos < 1 || start_pos > (int)jl_string_len(text) + 1) {
796792
// jl_bounds_error roots the arguments.
797-
jl_bounds_error((jl_value_t*)buf, jl_box_long(start_pos));
793+
jl_bounds_error(jl_box_long(start_pos), text);
798794
}
799-
else if (start_pos != 0 && rule == JL_PARSE_TOPLEVEL) {
795+
else if (start_pos != 1 && rule == JL_PARSE_TOPLEVEL) {
800796
jl_error("Partial parsing not support by top level grammar rule");
801797
}
802-
jl_value_t *expr=NULL, *pos1=NULL;
803-
JL_GC_PUSH2(&expr, &pos1);
804798

805-
// Call into flisp
806799
jl_ast_context_t *ctx = jl_ast_ctx_enter();
807800
fl_context_t *fl_ctx = &ctx->fl;
808-
value_t fl_content = cvalue_static_cstrn(fl_ctx, content, content_len);
809-
value_t fl_filename = cvalue_static_cstrn(fl_ctx, filename, filename_len);
801+
value_t fl_text = cvalue_static_cstrn(fl_ctx, jl_string_data(text),
802+
jl_string_len(text));
803+
value_t fl_filename = cvalue_static_cstrn(fl_ctx, jl_string_data(filename),
804+
jl_string_len(filename));
805+
value_t fl_expr;
806+
size_t pos1 = 0;
810807
if (rule == JL_PARSE_TOPLEVEL) {
811808
value_t e = fl_applyn(fl_ctx, 2, symbol_value(symbol(fl_ctx, "jl-parse-all")),
812-
fl_content, fl_filename);
813-
expr = e == fl_ctx->FL_EOF ? jl_nothing : scm_to_julia(fl_ctx, e, NULL);
814-
pos1 = e == fl_ctx->FL_EOF ? jl_box_long(content_len) : jl_box_long(0);
809+
fl_text, fl_filename);
810+
fl_expr = e;
811+
pos1 = e == fl_ctx->FL_EOF ? jl_string_len(text) : 0;
815812
}
816-
else if (rule == JL_PARSE_STATEMENTS || rule == JL_PARSE_ATOM) {
817-
value_t greedy = rule == JL_PARSE_STATEMENTS ?
818-
fl_ctx->T : fl_ctx->F;
813+
else if (rule == JL_PARSE_STATEMENT || rule == JL_PARSE_ATOM) {
814+
value_t greedy = rule == JL_PARSE_STATEMENT ? fl_ctx->T : fl_ctx->F;
815+
value_t offset = fixnum(start_pos-1);
819816
value_t p = fl_applyn(fl_ctx, 4, symbol_value(symbol(fl_ctx, "jl-parse-one")),
820-
fl_content, fl_filename, fixnum(start_pos), greedy);
821-
value_t e = car_(p);
822-
expr = e == fl_ctx->FL_EOF ? jl_nothing : scm_to_julia(fl_ctx, e, NULL);
823-
pos1 = jl_box_long(tosize(fl_ctx, cdr_(p), "parse"));
817+
fl_text, fl_filename, offset, greedy);
818+
fl_expr = car_(p);
819+
pos1 = tosize(fl_ctx, cdr_(p), "parse");
824820
}
825-
jl_ast_ctx_leave(ctx);
826-
827-
if (expr == NULL) {
828-
jl_errorf("Unknown grammar rule %d", (int)rule);
821+
else {
822+
jl_ast_ctx_leave(ctx);
823+
jl_errorf("Unknown parse rule %d", (int)rule);
829824
}
830825

831-
jl_value_t *result = (jl_value_t*)jl_svec2(expr, pos1);
826+
// Convert to julia values
827+
jl_value_t *expr=NULL, *end_pos=NULL;
828+
JL_GC_PUSH2(&expr, &end_pos);
829+
expr = fl_expr == fl_ctx->FL_EOF ? jl_nothing : scm_to_julia(fl_ctx, fl_expr, NULL);
830+
end_pos = jl_box_long(pos1 + 1);
831+
jl_ast_ctx_leave(ctx);
832+
jl_value_t *result = (jl_value_t*)jl_svec2(expr, end_pos);
832833
JL_GC_POP();
833834
return result;
834835
}
835836

836-
// parse an entire string like a file, reading multiple expressions
837-
JL_DLLEXPORT jl_value_t *jl_parse_all(const char *str, size_t len,
838-
const char *filename, size_t filename_len)
839-
{
840-
jl_value_t *p = jl_fl_parse(str, len, filename, filename_len,
841-
0, JL_PARSE_TOPLEVEL);
842-
return jl_svecref(p, 0);
843-
}
844-
845-
// this is for parsing one expression out of a string, keeping track of
846-
// the current position.
847-
JL_DLLEXPORT jl_value_t *jl_parse_string(const char *str, size_t len,
848-
int pos0, int greedy)
849-
{
850-
return jl_fl_parse(str, len, "none", 4, pos0,
851-
greedy ? JL_PARSE_STATEMENTS : JL_PARSE_ATOM);
852-
}
853-
854-
// deprecated
855-
JL_DLLEXPORT jl_value_t *jl_parse_input_line(const char *str, size_t len,
856-
const char *filename, size_t filename_len)
857-
{
858-
return jl_parse_all(str, len, filename, filename_len);
859-
}
860-
861837
// returns either an expression or a thunk
862838
jl_value_t *jl_call_scm_on_ast(const char *funcname, jl_value_t *expr, jl_module_t *inmodule)
863839
{

src/frontend.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
#include "julia.h"
4+
#include "julia_internal.h"
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
//------------------------------------------------------------------------------
11+
// Parsing
12+
13+
// Pointer to the current parser
14+
jl_parse_func_t jl_current_parser = NULL;
15+
16+
JL_DLLEXPORT void jl_set_parser(jl_parse_func_t parser)
17+
{
18+
jl_current_parser = parser;
19+
}
20+
21+
JL_DLLEXPORT jl_value_t *jl_parse(jl_value_t *text, jl_value_t *filename,
22+
int start_pos, int rule)
23+
{
24+
return (*jl_current_parser)(text, filename, start_pos, rule);
25+
}
26+
27+
// C API
28+
// parse an entire string like a file, reading multiple expressions
29+
JL_DLLEXPORT jl_value_t *jl_parse_all(const char *str, size_t len,
30+
const char *filename, size_t filename_len)
31+
{
32+
jl_value_t *text = NULL;
33+
jl_value_t *filename_ = NULL;
34+
JL_GC_PUSH2(&text, &filename_);
35+
text = jl_pchar_to_string(str, len);
36+
filename_ = jl_pchar_to_string(filename, filename_len);
37+
jl_value_t *p = jl_parse(text, filename_, 1, JL_PARSE_TOPLEVEL);
38+
JL_GC_POP();
39+
return jl_svecref(p, 0);
40+
}
41+
42+
// this is for parsing one expression out of a string, keeping track of
43+
// the current position.
44+
JL_DLLEXPORT jl_value_t *jl_parse_string(const char *str, size_t len,
45+
int pos0, int greedy)
46+
{
47+
jl_value_t *text = NULL;
48+
jl_value_t *filename_ = NULL;
49+
JL_GC_PUSH2(&text, &filename_);
50+
text = jl_pchar_to_string(str, len);
51+
filename_ = jl_cstr_to_string("none");
52+
jl_value_t *result = jl_parse(text, filename_, pos0+1,
53+
greedy ? JL_PARSE_STATEMENT : JL_PARSE_ATOM);
54+
JL_GC_POP();
55+
return result;
56+
}
57+
58+
// deprecated
59+
JL_DLLEXPORT jl_value_t *jl_parse_input_line(const char *str, size_t len,
60+
const char *filename, size_t filename_len)
61+
{
62+
return jl_parse_all(str, len, filename, filename_len);
63+
}
64+
65+
#ifdef __cplusplus
66+
}
67+
#endif

src/init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ void _julia_init(JL_IMAGE_SEARCH rel)
734734
#endif
735735
jl_init_common_symbols();
736736
jl_init_flisp();
737+
jl_set_parser(jl_fl_parse);
737738
jl_init_serializer();
738739

739740
if (!jl_options.image_file) {

src/julia.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,16 @@ JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *d
15971597
JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(const char *buf, size_t sz, jl_array_t *depmods);
15981598

15991599
// front end interface
1600+
typedef enum {
1601+
JL_PARSE_ATOM = 1,
1602+
JL_PARSE_STATEMENT = 2,
1603+
JL_PARSE_TOPLEVEL = 3,
1604+
} jl_parse_rule_t;
1605+
16001606
// parsing
1607+
JL_DLLEXPORT jl_value_t *jl_parse(jl_value_t *text, jl_value_t *filename,
1608+
int start_pos, int rule);
1609+
// TODO: Deprecate or convert to passing String to the next two?
16011610
JL_DLLEXPORT jl_value_t *jl_parse_all(const char *str, size_t len,
16021611
const char *filename, size_t filename_len);
16031612
JL_DLLEXPORT jl_value_t *jl_parse_string(const char *str, size_t len,
@@ -1611,7 +1620,7 @@ JL_DLLEXPORT jl_value_t *jl_expand_with_loc_warn(jl_value_t *expr, jl_module_t *
16111620
JL_DLLEXPORT jl_value_t *jl_expand_stmt(jl_value_t *expr, jl_module_t *inmodule);
16121621
JL_DLLEXPORT jl_value_t *jl_expand_stmt_with_loc(jl_value_t *expr, jl_module_t *inmodule,
16131622
const char *file, int line);
1614-
// deprecated; use jl_parse_all
1623+
// deprecated; use jl_parse
16151624
JL_DLLEXPORT jl_value_t *jl_parse_input_line(const char *str, size_t len,
16161625
const char *filename, size_t filename_len);
16171626

src/julia_internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,13 @@ jl_tupletype_t *arg_type_tuple(jl_value_t *arg1, jl_value_t **args, size_t nargs
638638

639639
int jl_has_meta(jl_array_t *body, jl_sym_t *sym);
640640

641+
// Parser replacement
642+
typedef jl_value_t* (*jl_parse_func_t)(jl_value_t*, jl_value_t*, int, int);
643+
JL_DLLEXPORT void jl_set_parser(jl_parse_func_t parser);
644+
// Builtin flisp parser
645+
JL_DLLEXPORT jl_value_t *jl_fl_parse(jl_value_t *text, jl_value_t *filename,
646+
int start_pos, int rule);
647+
641648
//--------------------------------------------------
642649
// Backtraces
643650

0 commit comments

Comments
 (0)