Skip to content

Commit cc2fc3f

Browse files
committed
Restricted pragma directives to only allow basic constructs for now
1 parent d399d3d commit cc2fc3f

File tree

4 files changed

+68
-7
lines changed

4 files changed

+68
-7
lines changed

Diff for: src/cli.rs

+2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ pub struct BuildOptions {
112112
pub interpret: bool,
113113
pub coerce_main_signature: bool,
114114
pub excute_result: bool,
115+
pub allow_experimental_pragma_features: bool,
115116
pub use_pic: Option<bool>,
116117
pub target: Target,
117118
pub infrastructure: Option<PathBuf>,
@@ -133,6 +134,7 @@ impl Default for BuildOptions {
133134
interpret: false,
134135
coerce_main_signature: true,
135136
excute_result: false,
137+
allow_experimental_pragma_features: false,
136138
use_pic: None,
137139
target: Target::HOST,
138140
infrastructure: Some(infrastructure),

Diff for: src/pragma_section/parse.rs

+63-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use super::PragmaSection;
22
use crate::{
3-
ast::{AstFile, Function, Parameters, StmtKind, TypeKind},
3+
ast::{AstFile, Expr, ExprKind, Function, Parameters, Stmt, StmtKind, TypeKind},
4+
diagnostics::ErrorDiagnostic,
45
inflow::Inflow,
56
parser::{self, error::ParseError, Input},
67
show::{into_show, Show},
8+
source_files::Source,
79
token::{Token, TokenKind},
810
};
911

1012
impl PragmaSection {
1113
pub fn parse<'a, I: Inflow<Token>>(
14+
allow_experimental_pragma_features: bool,
1215
mut input: Input<'a, I>,
1316
) -> Result<(PragmaSection, Input<'a, I>), Box<dyn Show>> {
1417
// pragma ...
@@ -33,11 +36,18 @@ impl PragmaSection {
3336
// "Whole-file" mode
3437

3538
// Parse top-level contructs until we hit a '}'
36-
while !parser.input.peek_is(TokenKind::CloseCurly) {
37-
parser
38-
.parse_top_level(&mut ast_file, vec![])
39-
.map_err(into_show)?;
40-
parser.input.ignore_newlines();
39+
if allow_experimental_pragma_features {
40+
while !parser.input.peek_is_or_eof(TokenKind::CloseCurly) {
41+
parser
42+
.parse_top_level(&mut ast_file, vec![])
43+
.map_err(into_show)?;
44+
parser.input.ignore_newlines();
45+
}
46+
} else {
47+
return Err(Box::new(ErrorDiagnostic::new(
48+
"Whole-file pragma directives are an experimental feature and may be removed",
49+
pragma_source,
50+
)));
4151
}
4252

4353
// Eat the final '}'
@@ -62,6 +72,12 @@ impl PragmaSection {
6272
vec![StmtKind::Expr(expr).at(expr_source)]
6373
};
6474

75+
if !allow_experimental_pragma_features {
76+
for stmt in stmts.iter() {
77+
restrict_allowed_stmt(stmt)?;
78+
}
79+
}
80+
6581
ast_file.functions.push(Function {
6682
name: "main".into(),
6783
parameters: Parameters {
@@ -92,3 +108,44 @@ impl PragmaSection {
92108
))
93109
}
94110
}
111+
112+
fn restrict_allowed_stmt(stmt: &Stmt) -> Result<(), Box<dyn Show>> {
113+
match &stmt.kind {
114+
StmtKind::Expr(inner) => restrict_allowed_expr(inner)?,
115+
_ => return Err(found_forbidden_stmt(stmt.source)),
116+
}
117+
118+
Ok(())
119+
}
120+
121+
fn restrict_allowed_expr(expr: &Expr) -> Result<(), Box<dyn Show>> {
122+
match &expr.kind {
123+
ExprKind::NullTerminatedString(_) => (),
124+
ExprKind::Call(call) => {
125+
if call.expected_to_return.is_some() {
126+
return Err(found_forbidden_expr(expr.source));
127+
}
128+
129+
for argument in call.arguments.iter() {
130+
restrict_allowed_expr(argument)?;
131+
}
132+
}
133+
_ => return Err(found_forbidden_expr(expr.source)),
134+
}
135+
136+
Ok(())
137+
}
138+
139+
fn found_forbidden_stmt(source: Source) -> Box<dyn Show> {
140+
Box::new(ErrorDiagnostic::new(
141+
"Support for this statement inside pragma directives is an experimental feature that may be removed",
142+
source,
143+
))
144+
}
145+
146+
fn found_forbidden_expr(source: Source) -> Box<dyn Show> {
147+
Box::new(ErrorDiagnostic::new(
148+
"Support for this expression inside pragma directives is an experimental feature that may be removed",
149+
source,
150+
))
151+
}

Diff for: src/pragma_section/run.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ impl PragmaSection {
2929
coerce_main_signature: false,
3030
excute_result: false,
3131
use_pic: None,
32+
allow_experimental_pragma_features: false,
3233
target: Target::HOST,
3334
infrastructure: None,
3435
},

Diff for: src/workspace/compile/module/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ pub fn compile_module_file<'a>(
3636
let mut settings = None;
3737

3838
while input.peek_is(TokenKind::PragmaKeyword) {
39-
let (section, rest_input) = PragmaSection::parse(input)?;
39+
let (section, rest_input) =
40+
PragmaSection::parse(compiler.options.allow_experimental_pragma_features, input)?;
4041
input = rest_input;
4142
settings = Some(section.run(compiler, path, settings)?);
4243
input.ignore_newlines();

0 commit comments

Comments
 (0)