Skip to content

Commit

Permalink
Add support for WithReference
Browse files Browse the repository at this point in the history
  • Loading branch information
flbulgarelli committed Feb 4, 2023
1 parent 0b7d41b commit 6ea23e4
Show file tree
Hide file tree
Showing 16 changed files with 46 additions and 12 deletions.
2 changes: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,15 @@ Finally, you can provide a _matcher_ to many of the available expectations, that

The complete list of supported matchers is the following:

* `WithAnything`
* `WithFalse`
* `WithLiteral`
* `WithLogic`
* `WithMath`
* `WithNil`
* `WithNonliteral`
* `WithTrue`
* `WithReference:value`
* `WithChar:'value'`
* `WithSymbol:value`
* `WithNumber:value`
Expand Down
1 change: 1 addition & 0 deletions gem/lib/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ en:
with_logic: ' with a boolean expression'
with_math: ' with a math expression'
with_nil: ' with <code>%{keyword_Nil}</code>'
with_reference: ' with <code>%{value}</code>'
with_nonliteral: ' with a non-literal expression'
with_number: ' with number <code>%{value}</code>'
with_string: ' with string <code>%{value}</code>'
Expand Down
1 change: 1 addition & 0 deletions gem/lib/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ es:
with_logic: ' con una expresión booleana'
with_math: 'con una expresión matemática'
with_nil: ' con <code>%{keyword_Nil}</code>'
with_reference: ' con <code>%{value}</code>'
with_nonliteral: ' con una expresión no literal'
with_number: ' con el número <code>%{value}</code>'
with_string: ' con la cadena <code>%{value}</code>'
Expand Down
1 change: 1 addition & 0 deletions gem/lib/locales/pt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pt:
with_logic: ' com uma expressão booleana'
with_math: ' com uma expressão matemática'
with_nil: ' com <code>%{keyword_Nil}</code>'
with_reference: ' com <code>%{value}</code>'
with_nonliteral: ' com uma expressão não literal'
with_number: ' com o número <code>%{value}</code>'
with_string: ' com a string <code>%{value}</code>'
Expand Down
2 changes: 1 addition & 1 deletion gem/lib/mulang/inspection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def as_json(*args)
(?<type>[^:]+)
(
:(?<matcher>WithAnything|WithLiteral|WithNonliteral|WithLogic|WithMath|WithFalse|WithNil|WithTrue) |
:(?<matcher>WithChar|WithNumber|WithString|WithSymbol):(?<value>[^:]+) |
:(?<matcher>WithReference|WithChar|WithNumber|WithString|WithSymbol):(?<value>[^:]+) |
:(?<target>[^:]+)(:(?<matcher>[^:]+)(:(?<value>[^:]+))?)?
)?$}.gsub(/\s/, '')

Expand Down
5 changes: 3 additions & 2 deletions gem/lib/mulang/inspection/matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ class Mulang::Inspection::Matcher
include Mulang::Inspection::Compacted

TYPES = %w(
WithAnything WithChar WithFalse WithLiteral WithLogic
WithMath WithNil WithNonliteral WithNumber WithString
WithAnything WithChar WithFalse WithLiteral
WithLogic WithMath WithNil WithNonliteral
WithNumber WithReference WithString
WithSymbol WithTrue)

attr_accessor :type, :value
Expand Down
5 changes: 4 additions & 1 deletion gem/spec/i18n_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def expectation(binding, inspection)
it { expect(expectation('*', 'CallsSetAt').translate).to eq('solution must use <code>[]=</code>') }
it { expect(expectation('*', 'CallsSetAt:WithAnything').translate).to eq('solution must use <code>[]=</code> with some expression') }
it { expect(expectation('*', 'CallsSetAt:WithLiteral').translate).to eq('solution must use <code>[]=</code> with a literal value') }
it { expect(expectation('*', 'CallsSetAt:WithReference:x').translate).to eq('solution must use <code>[]=</code> with <code>x</code>') }
end
end

Expand All @@ -91,6 +92,8 @@ def expectation(binding, inspection)

it { expect(expectation('*', 'DeclaresComputationWithArity1:foo').translate).to eq('<code>foo</code> deve ter um parâmetro') }

it { expect(expectation('*', 'CallsSlice:WithReference:nomes').translate :Python).to eq('a solução deve utilizar <code>[:]</code> com <code>nomes</code>') }

end

context 'es locale' do
Expand All @@ -117,7 +120,7 @@ def expectation(binding, inspection)
it { expect(expectation('foo', 'HasIf').translate(keyword_Repeat: 'repetir')).to eq('<code>foo</code> debe usar <code>if</code>') }

it { expect(expectation('*', 'CallsSize:WithNonliteral').translate :Python).to eq('la solución debe usar <code>len</code> con una expresión no literal') }
it { expect(expectation('*', 'CallsSize:WithNonliteral').translate :JavaScript).to eq('la solución debe usar <code>length</code> con una expresión no literal') }
it { expect(expectation('*', 'CallsSize:WithReference:y').translate :JavaScript).to eq('la solución debe usar <code>length</code> con <code>y</code>') }
end

describe 'custom expectations' do
Expand Down
1 change: 1 addition & 0 deletions gem/spec/inspection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
it { expect(Mulang::Inspection.parse("Returns:WithFalse")).to json_like(type: 'Returns', negated: false, matcher: {type: :with_false }) }
it { expect(Mulang::Inspection.parse("Returns:WithNil")).to json_like(type: 'Returns', negated: false, matcher: {type: :with_nil }) }
it { expect(Mulang::Inspection.parse("Returns:WithTrue")).to json_like(type: 'Returns', negated: false, matcher: {type: :with_true }) }
it { expect(Mulang::Inspection.parse("Returns:WithReference:c")).to json_like(type: 'Returns', negated: false, matcher: {type: :with_reference, value: "c" }) }
it { expect(Mulang::Inspection.parse("Returns:WithChar:'c'")).to json_like(type: 'Returns', negated: false, matcher: {type: :with_char, value: "'c'" }) }
it { expect(Mulang::Inspection.parse("Returns:WithNumber:2")).to json_like(type: 'Returns', negated: false, matcher: {type: :with_number, value: "2" }) }
it { expect(Mulang::Inspection.parse("Returns:WithString:'hooper'")).to json_like(type: 'Returns', negated: false, matcher: {type: :with_string, value: "'hooper'" }) }
Expand Down
1 change: 1 addition & 0 deletions spec/EdlSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ spec = do
test "within `bar` calls `foo` with (0, self)" (simpleMatchingWithin "bar" "calls" (Named "foo") (Matching [IsNumber 0, IsSelf]))
test "within `bar` calls `foo` with (\"hello\", self)" (simpleMatchingWithin "bar" "calls" (Named "foo") (Matching [IsString "hello", IsSelf]))
test "within `bar` calls `foo` with (`hello`, self)" (simpleMatchingWithin "bar" "calls" (Named "foo") (Matching [IsSymbol "hello", IsSelf]))
test "within `bar` calls `foo` with (&hello, self)" (simpleMatchingWithin "bar" "calls" (Named "foo") (Matching [IsReference "hello", IsSelf]))
test "within `bar` calls `foo` with ('a', self)" (simpleMatchingWithin "bar" "calls" (Named "foo") (Matching [IsChar 'a', IsSelf]))
test "within `bar` calls `foo` with (true, self)" (simpleMatchingWithin "bar" "calls" (Named "foo") (Matching [IsTrue, IsSelf]))
test "within `bar` calls `foo` with (false, self)" (simpleMatchingWithin "bar" "calls" (Named "foo") (Matching [IsFalse, IsSelf]))
Expand Down
4 changes: 4 additions & 0 deletions spec/ExpectationsCompilerSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ spec = do
run (Assignment "x" (MuSymbol "foo")) "*" "Assigns:x:WithSymbol:foo" `shouldBe` True
run (Assignment "x" (MuSymbol "foo")) "*" "Assigns:x:WithSymbol:bar" `shouldBe` False

it "works with Assigns WithReference" $ do
run (Assignment "x" (Reference "foo")) "*" "Assigns:x:WithReference:foo" `shouldBe` True
run (Assignment "x" (Reference "foo")) "*" "Assigns:x:WithReference:bar" `shouldBe` False

it "works with Assigns WithChar" $ do
run (java "class Foo { char x = 'a'; }") "Foo" "Assigns:x:WithChar:'a'" `shouldBe` True
run (java "class Foo { char x = 'b'; }") "Foo" "Assigns:x:WithChar:'a'" `shouldBe` False
Expand Down
1 change: 1 addition & 0 deletions src/Language/Mulang/Analyzer/EdlQueryCompiler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ compileClauses = withEvery . f
f :: [E.Clause] -> [Inspection]
f (E.IsAnything:args) = isAnything : (f args)
f (E.IsChar value:args) = isChar value : (f args)
f (E.IsReference value:args)= isReference value : (f args)
f (E.IsFalse:args) = isBool False : (f args)
f (E.IsLiteral:args) = isLiteral : (f args)
f (E.IsLogic:args) = usesLogic : (f args)
Expand Down
16 changes: 10 additions & 6 deletions src/Language/Mulang/Analyzer/ExpectationsCompiler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ compileCQuery :: [String] -> CQuery
compileCQuery [] = compileCQuery ["Parses","*"]
compileCQuery [verb] = compileCQuery [verb,"*"]
compileCQuery (verb:name:args) | Map.member name nullaryMatchers = compileCQuery (verb:"*":name:args)
compileCQuery (verb:"WithReference":args) = compileCQuery (verb:"*":"WithReference":args)
compileCQuery (verb:"WithChar":args) = compileCQuery (verb:"*":"WithChar":args)
compileCQuery (verb:"WithNumber":args) = compileCQuery (verb:"*":"WithNumber":args)
compileCQuery (verb:"WithString":args) = compileCQuery (verb:"*":"WithString":args)
Expand All @@ -53,13 +54,16 @@ compileMatcher = matching . f
matching [] = Unmatching
matching xs = Matching xs

readAsString value = read ("\""++value++"\"")

f :: [String] -> [Clause]
f (name:args) | Just matcher <- Map.lookup name nullaryMatchers = matcher : f args
f ("WithChar":value:args) = IsChar (read value) : f args
f ("WithNumber":value:args) = IsNumber (read value) : f args
f ("WithString":value:args) = IsString (read value) : f args
f ("WithSymbol":value:args) = IsSymbol (read ("\""++value++"\"")) : f args
f [] = []
f (name:args) | Just matcher <- Map.lookup name nullaryMatchers = matcher : f args
f ("WithReference":value:args) = IsReference (readAsString value) : f args
f ("WithChar":value:args) = IsChar (read value) : f args
f ("WithNumber":value:args) = IsNumber (read value) : f args
f ("WithString":value:args) = IsString (read value) : f args
f ("WithSymbol":value:args) = IsSymbol (readAsString value) : f args
f [] = []

nullaryMatchers =
Map.fromList [
Expand Down
1 change: 1 addition & 0 deletions src/Language/Mulang/Edl/Expectation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ data Clause
| IsNil
| IsNonliteral
| IsNumber Double
| IsReference String
| IsSelf
| IsString String
| IsSymbol String
Expand Down
9 changes: 7 additions & 2 deletions src/Language/Mulang/Edl/Lexer.x
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ tokens :-

"%%" ($not_eol_char)* ; -- skip comments

' @char ' { mkChar }
\" @string \" { mkString TString }
' @char ' { mkChar }
\" @string \" { mkString TString }
` @symbol ` { mkString TSymbol }
& @identifier { mkReference }
("+" | "-")? @float_number { token TNumber readFloat }
("+" | "-")? $digit+ { token TNumber (fromIntegral.readInt) }

Expand Down Expand Up @@ -134,6 +135,7 @@ data Token
| TOpenParen
| TOr
| TPlus
| TReference { referenceValue :: String }
| TSelf
| TSemi
| TSomething
Expand Down Expand Up @@ -217,4 +219,7 @@ mkString kind = token kind (\str -> drop 1 . take (length str - 1) $ str)

mkIdentifier :: Action
mkIdentifier = token TIdentifier id

mkReference :: Action
mkReference = token TReference (drop 1)
}
3 changes: 3 additions & 0 deletions src/Language/Mulang/Edl/Parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Control.Monad.Error

and { TAnd {} }
anything { TAnything {} }
reference { TReference {} }
atLeast { TAtLeast {} }
atMost { TAtMost {} }
cand { TCAnd {} }
Expand Down Expand Up @@ -161,6 +162,7 @@ Clauses : Clause { [$1] }
Clause :: { Clause }
Clause : number { IsNumber . numberValue $ $1 }
| string { IsString . stringValue $ $1 }
| reference { IsReference . referenceValue $ $1 }
| char { IsChar . charValue $ $1 }
| symbol { IsSymbol . symbolValue $ $1 }
| anything { IsAnything }
Expand Down Expand Up @@ -194,6 +196,7 @@ scopeOperatorError operator = unlines [
m (TChar v) = "char " ++ show v ++ " is not expected here"
m (TIdentifier id) = "Unexpected keyword " ++ id
m (TNumber v) = "number " ++ show v ++ " is not expected here"
m (TReference v) = "reference " ++ show v ++ " is not expected here"
m (TString v) = "string " ++ show v ++ " is not expected here"
m (TSymbol v) = "symbol " ++ v ++ " is not expected here"
m TAnd = "and is not expected here"
Expand Down
5 changes: 5 additions & 0 deletions src/Language/Mulang/Inspector/Literal.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Language.Mulang.Inspector.Literal (
isAnything,
isBool,
isReference,
isChar,
isNil,
isNumber,
Expand Down Expand Up @@ -33,6 +34,10 @@ isNumber = (==) . MuNumber
isBool :: Bool -> Inspection
isBool = (==) . MuBool

isReference :: String -> Inspection
isReference = (==) . Reference


isString :: String -> Inspection
isString = (==) . MuString

Expand Down

0 comments on commit 6ea23e4

Please sign in to comment.