Skip to content

Commit

Permalink
Merge pull request #14 from smuuf/strict
Browse files Browse the repository at this point in the history
Handling of strings and numbers is now strict
  • Loading branch information
smuuf authored Oct 14, 2018
2 parents 2bf3004 + 17f48f9 commit 009cf91
Show file tree
Hide file tree
Showing 29 changed files with 108 additions and 90 deletions.
2 changes: 1 addition & 1 deletion docs/language_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Example usage:
a = true;
b = 1 == 2; // false
c = b == false; // true
d = c == "hello"; // ERR: Cannot compare: 'bool' and 'string' @ code: c == "hello"
d = c == "hello"; // ERR: Cannot compare 'bool' and 'string'
e = "hello" == r"[0-9]"; // false
f = "hello" == r"l{2}"; // true
```
Expand Down
2 changes: 1 addition & 1 deletion example/04.primi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
a = 4 / (2 - 1) * 100;
damn = 153 * 2;

c = "zaplaťte pouze " + a + " Kč za skvělou " + damn;
c = "zaplaťte pouze " + to_string(a) + " Kč za skvělou " + damn.to_string();
g = 1;

while (damn > 10) {
Expand Down
2 changes: 1 addition & 1 deletion example/08.primi
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function sub(x, y) {
}

a = 1 + add(sub(4, 3), 3);
a + "\n";
a.to_string() + "\n";

function nested(a) {
return add(a, sub(2,3));
Expand Down
6 changes: 3 additions & 3 deletions example/09.primi
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ function sub(x, y) {

}

a = 1 + add(sub(4, 3), 3);
a = (1 + add(sub(4, 3), 3)).to_string();
a = a + "\n";

a = 4 / (2 - 1) * 100;
damn = 153 * 2;
c = "zaplaťte pouze " + a + " Kč za skvělou " + damn;
c = "zaplaťte pouze " + a.to_string() + " Kč za skvělou " + to_string(damn);

g = 1;
d = 2;
Expand All @@ -86,7 +86,7 @@ while (damn < 10000) {
");

damn = damn * d - 1 * d;
c = g + "0";
c = g + to_number("0");

if (c - 4 * 2) {
if (4 + (123 * 7) / 8) {
Expand Down
14 changes: 7 additions & 7 deletions example/bench_all.primi
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

a = 1 + 2;
b = "1" + 2;
c = 1 + "2";
d = "x" + 1;
e = 1 + "x";
b = to_number("1") + 2;
c = to_string(1) + "2";
d = "x".to_number() + 1;
e = to_string(1) + "x";
f = "x" + "1";
g = "1" + "x";
h = "abc" + " def";
Expand Down Expand Up @@ -91,8 +91,8 @@ d = 1 * "2";
e = 1 * "2.4";
f = 8 / 4;
g = 4 / 16;
h = 123 / a;
i = 123 / b;
h = 123 / to_number(a);
i = 123 / to_number(b);
j = (1 + (3 / (4 - 5)) + 2 / (37 * 2 / 8 - 42));
k = 1 + 2 * 3 / 4 - 5 / 6 * 7 + 8;
a = "abcdefg";
Expand Down Expand Up @@ -141,7 +141,7 @@ _definitions = [
];
f = "rádoby čau".string_replace(_definitions);
g = "vole".string_replace("v", "l").string_replace("o", "i") + "k";
h = ("číslo je " + 000.cos()).string_replace(["č": "c", "í": "i"]);
h = ("číslo je " + 000.cos().to_string()).string_replace(["č": "c", "í": "i"]);
i = "kokot je " + "oo".string_replace("o", "e");
a_1 = 9.sqrt();
b_1 = 3.pow();
Expand Down
23 changes: 20 additions & 3 deletions src/Repl.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use \Smuuf\Primi\Helpers\Common;
use \Smuuf\Primi\Colors;
use \Smuuf\Primi\Interpreter;
use \Smuuf\Primi\IContext;
use \Smuuf\Primi\IReadlineDriver;

class Repl extends \Smuuf\Primi\StrictObject {
Expand Down Expand Up @@ -56,12 +57,19 @@ public function start() {
private function loop() {

$i = $this->interpreter;
$c = $i->getContext();

readline_completion_function(function() { return []; });

while (true) {

$input = $this->gatherLines();

switch (trim($input)) {
case '?':
$this->printContext($c);
continue 2;
break;
case '':
// Ignore (skip) empty input.
continue 2;
Expand Down Expand Up @@ -91,7 +99,7 @@ private function loop() {

}

public function printResult(Value $result = null): void {
private function printResult(Value $result = null): void {

if ($result === null) {
return;
Expand All @@ -100,12 +108,12 @@ public function printResult(Value $result = null): void {
printf(
"%s %s\n",
$result->getStringValue(),
!$this->rawOutput ? $this->formatType($result) : null
!$this->rawOutput ? self::formatType($result) : null
);

}

private function formatType(Value $value) {
private static function formatType(Value $value) {

return Colors::get(sprintf(
"{darkgrey}(%s %s){_}",
Expand All @@ -115,6 +123,15 @@ private function formatType(Value $value) {

}

private function printContext(IContext $c): void {

foreach ($c->getVariables() as $name => $value) {
echo "$name: ";
$this->printResult($value);
}

}

private function gatherLines(): string {

$gathering = false;
Expand Down
2 changes: 1 addition & 1 deletion src/extensions/psl/CastingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static function to_string(Value $value): StringValue {
public static function to_regex(Value $value): RegexValue {

// Allow regexes to be casted to regex.
if ($value instanceof Regex) {
if ($value instanceof RegexValue) {
return $value;
}

Expand Down
4 changes: 2 additions & 2 deletions src/handlers/Addition.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public static function handle(array $node, Context $context) {
} catch (InternalBinaryOperationxception $e) {

throw new ErrorException(sprintf(
"Cannot %s types '%s' and '%s'",
$e->getOperator() === "+" ? "add" : "subtract",
"Cannot use operator '%s' with '%s' and '%s'",
$e->getOperator(),
($e->getLeft())::TYPE,
($e->getRight())::TYPE
), $node);
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/Comparison.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static function handle(array $node, Context $context) {
} catch (\TypeError $e) {

throw new ErrorException(sprintf(
"Cannot compare types '%s' and '%s'",
"Cannot compare '%s' and '%s'",
$leftReturn::TYPE,
$rightReturn::TYPE
), $node);
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/ForeachStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static function handle(array $node, Context $context) {

if (!$subject instanceof ISupportsIteration) {
throw new \Smuuf\Primi\ErrorException(
"Cannot iterate over '{$node['left']['text']}' variable",
sprintf("Cannot iterate over '%s'", $subject::TYPE),
$node
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/Invocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private static function buildArgumentCountErrorMessage(
} else {

throw new InternalException(
"Cannot parse argument count from unexpected exception."
"Cannot parse argument count from unexpected exception"
);

}
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/Multiplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public static function handle(array $node, Context $context) {
} catch (InternalBinaryOperationxception $e) {

throw new ErrorException(sprintf(
"Cannot %s types '%s' and '%s'",
$e->getOperator() === "*" ? "multiply" : "divide",
"Cannot use operator '%s' with '%s' and '%s'",
$e->getOperator(),
($e->getLeft())::TYPE,
($e->getRight())::TYPE
), $node);
Expand Down
4 changes: 0 additions & 4 deletions src/handlers/StringLiteral.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ public static function handle(array $node, Context $context) {
// so do this a little more directly.
$value = \mb_substr($content, 1, \mb_strlen($content) - 2);

if (NumberValue::isNumeric($value)) {
return new NumberValue($value);
}

return new StringValue($value);

}
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/Vector.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static function chain(

if (!$subject instanceof ISupportsArrayAccess) {
throw new ErrorException(sprintf(
"Cannot perform array-like write on '%s'",
"Cannot insert into '%s'",
$subject::TYPE
), $node);
}
Expand Down
8 changes: 7 additions & 1 deletion src/helpers/Common.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ public static function allowTypes(?Value $value, string ...$types) {
}

// The value did not match any of the types provided.
throw new \TypeError;
$msg = sprintf(
"'%s' is not any of these: %s",
$value::TYPE,
implode(", ", $types)
);

throw new \TypeError($msg);

}

Expand Down
2 changes: 1 addition & 1 deletion src/structures/ArrayInsertionProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public function commit(Value $value) {
$this->target->arraySet($this->key, $value);
} catch (\TypeError $e) {
throw new ErrorException(sprintf(
"Cannot insert type '%s' into type '%s'",
"Cannot insert '%s' into '%s'",
$value::TYPE,
$this->target::TYPE
));
Expand Down
22 changes: 14 additions & 8 deletions src/structures/NumberValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,7 @@ public static function isNumeric(string $input): bool {

public function doAddition(Value $rightOperand): Value {

Common::allowTypes($rightOperand, self::class, StringValue::class);

if ($rightOperand instanceof StringValue && !self::isNumeric($rightOperand->value)) {
return new StringValue($this->value . $rightOperand->value);
}

Common::allowTypes($rightOperand, self::class);
return new self($this->value + $rightOperand->value);

}
Expand All @@ -75,7 +70,8 @@ public function doMultiplication(Value $rightOperand) {
if ($rightOperand instanceof StringValue) {
$multiplier = $this->value;
if (\is_int($multiplier) && $multiplier >= 0) {
return new StringValue(\str_repeat($rightOperand->value, $multiplier));
$new = \str_repeat($rightOperand->value, $multiplier);
return new StringValue($new);
}
throw new \TypeError;
}
Expand All @@ -90,7 +86,7 @@ public function doDivision(Value $rightOperand): self {

// Avoid division by zero.
if ($rightOperand->value === 0) {
throw new \Smuuf\Primi\ErrorException("Division by zero.");
throw new \Smuuf\Primi\ErrorException("Division by zero");
}

return new self($this->value / $rightOperand->value);
Expand All @@ -114,10 +110,20 @@ public function doComparison(string $op, Value $rightOperand): BoolValue {

Common::allowTypes($rightOperand, self::class, StringValue::class);

// Numbers and strings can be only compared for equality.
// And are never equal.
if ($rightOperand instanceof StringValue) {
if ($op !== "==" && $op !== "!=") {
throw new \TypeError;
}
}

switch ($op) {
case "==":
// Don't do strict - wrong comparison of float and int.
return new BoolValue($this->value == $rightOperand->value);
case "!=":
// Don't do strict - wrong comparison of float and int.
return new BoolValue($this->value != $rightOperand->value);
case ">":
return new BoolValue($this->value > $rightOperand->value);
Expand Down
27 changes: 19 additions & 8 deletions src/structures/StringValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,24 @@ public function getStringValue(): string {

public function doAddition(Value $rightOperand) {

Common::allowTypes($rightOperand, self::class, NumberValue::class);
Common::allowTypes($rightOperand, self::class);
return new self($this->value . $rightOperand->value);

}

public function doSubtraction(Value $rightOperand) {

// Allow only string at this point (if the operand was a regex, we've
// already returned value).
Common::allowTypes($rightOperand, self::class, RegexValue::class);

if ($rightOperand instanceof RegexValue) {
return new self(\preg_replace($rightOperand->value, \null, $this->value));
$match = \preg_replace($rightOperand->value, \null, $this->value);
return new self($match);
}

// Allow only string at this point (if the operand was a regex, we've already returned value).
Common::allowTypes($rightOperand, self::class);

return new self(\str_replace($rightOperand->value, \null, $this->value));
$new = \str_replace($rightOperand->value, \null, $this->value);
return new self($new);

}

Expand All @@ -78,13 +81,21 @@ public function doComparison(string $op, Value $rightOperand): BoolValue {
NumberValue::class
);

// Numbers and strings can be only compared for equality.
// And are never equal.
if ($rightOperand instanceof NumberValue) {
if ($op !== "==" && $op !== "!=") {
throw new \TypeError;
}
}

switch ($op) {
case "==":

if ($rightOperand instanceof RegexValue) {
$result = \preg_match($rightOperand->value, $this->value);
} else {
$result = $this->value === (string) $rightOperand->value;
$result = $this->value === $rightOperand->value;
}

break;
Expand All @@ -93,7 +104,7 @@ public function doComparison(string $op, Value $rightOperand): BoolValue {
if ($rightOperand instanceof RegexValue) {
$result = !\preg_match($rightOperand->value, $this->value);
} else {
$result = $this->value !== (string) $rightOperand->value;
$result = $this->value !== $rightOperand->value;
}

break;
Expand Down
3 changes: 3 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

\Smuuf\Primi\ExtensionHub::add([
\Smuuf\Primi\Psl\StringExtension::class,
\Smuuf\Primi\Psl\BoolExtension::class,
\Smuuf\Primi\Psl\RegexExtension::class,
\Smuuf\Primi\Psl\NumberExtension::class,
\Smuuf\Primi\Psl\ArrayExtension::class,
\Smuuf\Primi\Psl\CastingExtension::class,
]);

\Tester\Environment::setup();
6 changes: 2 additions & 4 deletions tests/language/suites/operations/addition.expect
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
a:NumberValue:3
b:NumberValue:3
c:NumberValue:3
d:StringValue:"x1"
e:StringValue:"1x"
b:StringValue:"12"
c:NumberValue:444
f:StringValue:"x1"
g:StringValue:"1x"
h:StringValue:"abc def"
Expand Down
Loading

0 comments on commit 009cf91

Please sign in to comment.