Skip to content

Commit

Permalink
Fix usage of reserved keyword in condition
Browse files Browse the repository at this point in the history
Ref. eng/recordflux/RecordFlux#1715
  • Loading branch information
Volham22 committed Aug 1, 2024
1 parent 9fd9601 commit 7bddb42
Show file tree
Hide file tree
Showing 12 changed files with 200 additions and 99 deletions.
11 changes: 11 additions & 0 deletions librapidflux/src/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ impl std::cmp::PartialEq for ID {
}
}

impl AsRef<str> for ID {
fn as_ref(&self) -> &str {
&self.identifier
}
}

#[derive(Debug, PartialEq)]
pub struct IDRef<'a> {
identifier: &'a str,
Expand Down Expand Up @@ -378,6 +384,11 @@ mod tests {
assert_eq!(id(left, None) == id(right, None), expected);
}

#[test]
fn test_id_as_ref() {
assert_eq!(id("foo", None).as_ref(), "foo");
}

#[test]
fn test_id_ref_to_owned() {
let identifier = "A::B".to_string();
Expand Down
4 changes: 4 additions & 0 deletions rapidflux/src/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ impl ID {
PyBool::new_bound(py, self.0 == other_id.0)
.to_owned()
.into()
} else if let Ok(other_str) = other.extract::<&str>() {
PyBool::new_bound(py, self.0.as_ref() == other_str)
.to_owned()
.into()
} else {
PyNotImplemented::get_bound(py).to_owned().into()
}
Expand Down
84 changes: 84 additions & 0 deletions rflx/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,87 @@
# The use of "forkserver" or "spawn" as start method for starting processes prevents deadlocks when
# RecordFlux is executed by another process, e.g., when the language server is started by VS Code.
MP_CONTEXT = multiprocessing.get_context("forkserver")

RESERVED_WORDS = [
# Ada
"abort",
"abs",
"abstract",
"accept",
"access",
"aliased",
"all",
"and",
"array",
"at",
"begin",
"body",
"case",
"constant",
"declare",
"delay",
"delta",
"digits",
"do",
"else",
"elsif",
"end",
"entry",
"exception",
"exit",
"for",
"function",
"generic",
"goto",
"if",
"in",
"interface",
"is",
"limited",
"loop",
"mod",
"new",
"not",
"null",
"of",
"or",
"others",
"out",
"overriding",
"package",
"parallel",
"pragma",
"private",
"procedure",
"protected",
"raise",
"range",
"record",
"rem",
"renames",
"requeue",
"return",
"reverse",
"select",
"separate",
"some",
"subtype",
"synchronized",
"tagged",
"task",
"terminate",
"then",
"type",
"until",
"use",
"when",
"while",
"with",
"xor",
# Code generation
"initial",
"final",
"ctx",
"val",
"enum",
]
4 changes: 2 additions & 2 deletions rflx/converter/iana.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@

from defusedxml import ElementTree

import rflx.specification.const
import rflx.const
from rflx.common import file_name
from rflx.error import fail, warn
from rflx.rapidflux import Location, RecordFluxError

NAMESPACE = {"iana": "http://www.iana.org/assignments"}
RESERVED_WORDS = "|".join(rflx.specification.const.RESERVED_WORDS)
RESERVED_WORDS = "|".join(rflx.const.RESERVED_WORDS)
OUTPUT_INDENT_CHAR = " "
OUTPUT_INDENT = OUTPUT_INDENT_CHAR * 3
OUTPUT_WIDTH = 80
Expand Down
1 change: 0 additions & 1 deletion rflx/ls/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ def update(self, document_uri: str) -> None:
self._error.extend(e.entries)

unchecked_model = parser.create_unchecked_model()

self._error.extend(unchecked_model.error.entries)

self._publish_errors_as_diagnostics(self._error)
Expand Down
14 changes: 6 additions & 8 deletions rflx/model/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -1533,14 +1533,12 @@ def _verify_message_types(self) -> None:
continue
for var in expression.variables():
if var.type_ == rty.Undefined():
self.error.extend(
[
ErrorEntry(
f'undefined variable "{var.identifier}"',
Severity.ERROR,
var.location,
),
],
self.error.push(
ErrorEntry(
f'undefined variable "{var.identifier}"',
Severity.ERROR,
var.location,
),
)

def _verify_expression_types(self, valid_paths: set[tuple[Link, ...]]) -> None:
Expand Down
83 changes: 0 additions & 83 deletions rflx/specification/const.py

This file was deleted.

12 changes: 11 additions & 1 deletion rflx/specification/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import rflx.typing_ as rty
from rflx import expr, lang, model
from rflx.common import STDIN, unique
from rflx.const import RESERVED_WORDS
from rflx.error import fail
from rflx.identifier import ID, StrID
from rflx.integration import Integration
Expand All @@ -23,7 +24,6 @@
logging,
source_code,
)
from rflx.specification.const import RESERVED_WORDS

from . import style

Expand Down Expand Up @@ -336,6 +336,16 @@ def create_id(error: RecordFluxError, identifier: lang.AbstractID, filename: Pat
)
* name
)

if name.parts[0].lower() in RESERVED_WORDS:
error.push(
ErrorEntry(
f'reserved word "{name}" used as identifier',
Severity.ERROR,
node_location(identifier, filename),
),
)

return name

raise NotImplementedError(f"Invalid ID: {identifier.text} {type(identifier)}")
Expand Down
56 changes: 56 additions & 0 deletions tests/integration/specification_model_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

from rflx import expr, typing_ as rty
from rflx.const import RESERVED_WORDS
from rflx.identifier import ID
from rflx.model import (
BOOLEAN,
Expand Down Expand Up @@ -2151,3 +2152,58 @@ def test_parameter_non_scalar_and_builtin_type(
),
capfd,
)


@pytest.mark.parametrize(
"keyword",
RESERVED_WORDS,
)
def test_reserved_word_link_condition(
tmp_path: Path,
capfd: pytest.CaptureFixture[str],
keyword: str,
) -> None:
file_path = tmp_path / "test.rflx"
file_path.write_text(
textwrap.dedent(
f"""\
package Test is
type I is range 0 .. 255 with Size => 8;
type M (A : Boolean) is
message
X : Boolean
then Z
if A and {keyword};
Z : Opaque
with Size => 8;
end message;
end Test;
""",
),
)
assert_error_full_message(
file_path,
textwrap.dedent(
f"""\
info: Parsing {file_path}
info: Processing Test
info: Verifying __BUILTINS__::Boolean
info: Verifying __INTERNAL__::Opaque
info: Verifying Test::I
info: Verifying Test::M
error: reserved word "{keyword}" used as identifier
--> {file_path}:7:25
|
7 | if A and {keyword};
| {"^".rjust(len(keyword), "^")}
|
error: undefined variable "{keyword}"
--> {file_path}:7:25
|
7 | if A and {keyword};
| {"^".rjust(len(keyword), "^")}
|
""",
),
capfd,
)
3 changes: 1 addition & 2 deletions tests/property/strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from hypothesis import assume, strategies as st

from rflx import expr, typing_ as rty
from rflx import const, expr, typing_ as rty
from rflx.identifier import ID
from rflx.model import (
BUILTIN_TYPES,
Expand All @@ -28,7 +28,6 @@
TypeDecl,
)
from rflx.rapidflux import ErrorEntry, Location, RecordFluxError, Severity
from rflx.specification import const

T = TypeVar("T")

Expand Down
2 changes: 0 additions & 2 deletions tests/unit/specification/const_test.py

This file was deleted.

Loading

0 comments on commit 7bddb42

Please sign in to comment.