Setting types of parsed values in Antlr - antlr4

I have a rule that looks like this:
INTEGER : [0-9]+;
myFields : uno=INTEGER COMMA dos=INTEGER
Right now to access uno I need to code:
Integer i = Integer.parseInt(myFields.uno.getText())
It would be much cleaner if I could tell antler to do that conversion for me; then I would just need to code:
Integer i = myFields.uno
What are my options?

You could write the code as action, but it would still be explicit conversion (eventually). The parser (like every parser) parses the text and then it's up to "parsing events" (achieved by listener or visitor or actions in ANTLR4) to create meaningful structures/objects.
Of course you could extend some of the generated or built-in classes and then get the type directly, but as mentioned before, at some point you'll always need to convert text to some type needed.

A standard way of handling custom operations on tokens is to embed them in a custom token class:
public class MyToken extends CommonToken {
....
public Integer getInt() {
return Integer.parseInt(getText()); // TODO: error handling
}
}
Also create
public class MyTokenFactory extends TokenFactory { .... }
to source the custom tokens. Add the factory to the lexer using Lexer#setTokenFactory().
Within the custom TokenFactory, override the method
Symbol create(int type, String text); // (typically override both factory methods)
to construct and return a new MyToken.
Given that the signature includes the target token type type, custom type-specific token subclasses could be returned, each with their own custom methods.
Couple of issues with this, though. First, in practice, it is not typically needed: the assignment var is statically typed, so as in the the OP example,
options { TokenLabelType = "MyToken"; }
Integer i = myFields.uno.getInt(); // no cast required
If Integer is desired & expected, use getInt(). If Boolean ....
Second, ANTLR options allows setting a TokenLabelType to preclude the requirement to manually cast custom tokens. Use of only one token label type is supported. So, to use multiple token types, manual casting is required.

Related

Equivalent to DateTime.Parse in NodaTime?

If I have a string like "2020-12-15T12:10:00.202" how can I parse this into NodaTime.LocalDateTime directly, rather than doing something like:
LocalDateTime.FromDateTime(DateTime.Parse("2020-12-15T12:10:00.202"))
And similarly for the other NodaTime types like LocalDate, Instant etc.
You use a LocalDateTimePattern. For example:
// Note: patterns are thread-safe and immutable. Various patterns are provided as
// static properties on the relevant pattern class. If you can't use one of those
// patterns, it's often useful to store the pattern in a static readonly field.
var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd'T'HH:mm:ss.fff");
// There's no Parse/TryParse separation - there's just Parse, which returns a
// ParseResult<T> that indicates success/failure.
ParseResult<LocalDateTime> parsed = pattern.Parse("2020-12-15T12:10:00.202");
// Note: if you're okay with invalid input causing an exception, just use
// parsed.Value directly - it will throw a descriptive exception if parsing failed.
if (parsed.Success)
{
LocalDateTime result = parsed.Value;
// Use the result here
}
else
{
// Handle the failure
}
For more details about text handling, see the section in the user guide.
Note that there's no direct equivalent of DateTime.Parse itself, that tries multiple different date/time formats automatically - but you can use a CompositePatternBuilder<T> to try multiple patterns when parsing if you want.

TS: Cannot invoke an expression whose type lacks a call signature when defined dynamically, but it works

I'm still quite new to typescript, so please be gentle with me if I'm doing something with no sense for this technology!
The problem that I'm trying to solve is having a dynamic way to define how my application errors should be structured, but leaving to the users the faculty to enrich the messages.
So I tried to create this logic in a module that could be extended easily from the application, but I'm currently facing the problem:
Error:(35, 18) TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'ErrorMessage' has no compatible call signatures.
What I thought it was a good idea (but please tell me if I'm wrong), was to use a register and a map to have the possibility to extend this mapping every time I want. So I created my ErrorMessage interface to be like the following:
export interface ErrorMessage {
actionMessage: string;
actionSubject: string;
originalErrorMessage?: string;
toString: () => string;
}
and a register for these, called ErrorResponseRegister, as it follows:
export enum defaultErrors {
ExceptionA = 'ExceptionA',
ExceptionB = 'ExceptionB',
}
export class ErrorResponseRegister {
private mapping: Map<string, ErrorMessage>;
constructor() {
this.mapping = new Map()
.set(defaultErrors.ExceptionA, exceptionAErrorMessage)
.set(defaultErrors.ExceptionB, exceptionBErrorMessage);
}
}
So at the end, every ErrorMessage function should look like:
export function exceptionAErrorMessage(originalErrorMessage?: string): ErrorMessage {
return {
enrichment1: "Something happened",
enrichment2: "in the application core",
originalErrorMessage: originalErrorMessage,
toString(): string {
return `${this.enrichment1} ${this.enrichment2}. Original error message: ${originalErrorMessage}`;
},
};
}
Please note I haven't used classes for this ones, as it doesn't really need to be instantiated
and I can have a bunch of them where the toString() method can vary. I just want to enforce the errors should have an enrichment1 and enrichment2 that highlight the problem in a better way for not-technical people.
So, now, back to code. When I'm trying to use the exceptionAErrorMessage statically, I can't see any problem:
console.log(exceptionAErrorMessage(originalErrorMessage).toString())
But when I try dynamically, using the map defined in the ErrorResponseRegister, something weird happens:
// In ErrorResponseRegister
public buildFor(errorType: string, originalErrorMessage?: string): Error {
const errorMessageBuilder = this.mapping.get(errorType);
if (errorMessageBuilder) {
return errorMessageBuilder(originalErrorMessage).toString();
}
return "undefined - do something else";
}
The code works as expected, the error returned is in the right format, so the toString function is executed correctly.
BUT, the following error appears in the IDE:
Error:(32, 18) TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'ErrorMessage' has no compatible call signatures.
The line that causes the problem is
errorMessageBuilder(originalPosErrorMessage).toString()
Can someone help me to understand what I'm doing wrong?
It looks like your problem is you've mistyped mapping... it doesn't hold ErrorMessage values; it holds (x?: string)=>ErrorMessage values:
private mapping: Map<string, (x?: string) => ErrorMessage>;
What's unfortunate is that you initialize this variable via new Map().set(...) instead of the using an iterable constructor argument.
The former returns a Map<any, any> which is trivially assignable to mapping despite the mistyping. That is, you ran smack into this known issue where the standard library's typings for the no-argument Map constructor signature produces Map<any, any> which suppresses all kinds of otherwise useful error messages. Perhaps that will be fixed one day, but for now I'd suggest instead that you use the iterable constructor argument, whose type signature declaration will infer reasonable types for the keys/values:
constructor() {
this.mapping = new Map([
[defaultErrors.ExceptionA, exceptionAErrorMessage],
[defaultErrors.ExceptionB, exceptionBErrorMessage]
]); // inferred as Map<defaultErrors, (orig?: string)=>ErrorMessage>
}
If you had done so, it would have flagged the assignment as an error with your original typing for mapping (e.g., Type 'Map<defaultErrors, (originalErrorMessage?: string | undefined) => ErrorMessage>' is not assignable to type 'Map<string, ErrorMessage>'.) Oh well!
Once you make those changes, things should behave more reasonably for you. Hope that helps; good luck!
Link to code

Forward operators in haxe

I'm trying to write my own boolean "abstract" with some additional functions.
#forward
abstract MyBool(Bool) {
public inline function new(b:Bool) {
this = b;
}
#:from
public static inline function fromBool(b:Bool):MyBool {
return new MyBool(b);
}
#:to
public inline function toBool():Bool {
return this;
}
// some additional functions
}
In principal this works fine:
var t:T = true;
if(t) {
trace("1");
}
t.someStrangeMethod();
However #:forward does not forward basic boolean-operators like "!":
var f:T = false;
if(!f) { // fails here, because "!" is not defined as an operator for MyBool ...
trace("2");
}
The error message is "MyBool should be Bool", which I find quite strange because MyBool is an abstract of a Bool with #:forward annotation and there is a #:to-method.
Of course there are some easy workarounds. One could either use:
if(!f.toBool()) {
trace("2");
}
and/or add a function annotated with #:op(!A) to the abstract:
#:op(!A)
public inline function notOp():Bool {
return !this;
}
However I do not like both methods:
I dislike adding #:op(...) to MyBool, because creating a method for each possible operator would require much code (Maybe not with a boolean, but e.g. with an Int, Float, ...).
I dislike using !var.toBool(). If someone has already written quite some code (s)he does not want to go through all of it, when (s)he simply wants to change Bool to a MyBool ... I mean of course (s)he could also cast Bool to MyBool whenever adding new code, but that can be horrible too.
So I was wondering if anyone has a better idea? Is there maybe another "#:forward"-like compiling metadata, I do not know about yet?
There's an open feature request regarding this:
Can #:forward also forward underlying operator overloads? (#5035)
One way to make your code example work is to allow implicit conversions with to Bool. I'm not entirely sure why the equivalent #:to function doesn't work here, as the Haxe Manual states that "Class field casts have the same semantics".
abstract MyBool(Bool) to Bool {
Apart from that, I think the only options is to declare an #:op function for each operator you want to support. If declared without a body, the underlying type's operator will be forwarded:
#:op(!A) function notOp():MyBool;
If your main goal is to just add methods to the Bool type, then perhaps avoid the problem altogether by instead creating a class that adds methods to Bool via static extension (documented in the Haxe manual). This method would eliminate the need for operator forwarding.

Specify RequiredCreationPolicy for non-Attributed Imports

I have an IoC wrapper that uses MEF as it's DI container, an applicable snippet of the wrapper is shown below.
public static bool TryGetComponent<T>(out T component)
{
CompositionContainer container = RetrieveContainer();
T retrievedComponent = container.GetExportedValueOrDefault<T>();
if (retrievedComponent.Equals(default(T)))
{
component = default(T);
return false;
}
component = retrievedComponent;
return true;
}
Most of the exported components in the CompositionContainer specify a CreationPolicy of "Any".
[PartCreationPolicy(CreationPolicy.Any)]
For types that I create I can easily use the following import attribute to get MEF to serve the exported types as NonShared instances.
[Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
However, since my IoC wrapper must also be used by classes that do not use MEF or any of its Import attributes and must use my IoC API to obtain instances exported types. I need a way to specify the CreationPolicy when I programmatically use the CompositionContainer to GetExports and GetExportedValues. Is this even possible without using import attributes?
If you really want to query the container exactly like as if you had a ImportAttribute with RequiredCreationPolicy=NonShared then try creating your own custom ContractBasedImportDefinition. One of the parameters for to the contructor is a CreationPolicy that represents the required creation policy.
Something like:
container.GetExports(new ContractBasedImportDefinition(
AttributedModelServices.GetContractName(type),
AttributedModelServices.GetTypeIdentity(type),
null,
ImportCardinality.ZeroOrMore,
false,
false,
CreationPolicy.NonShared));
Of course you can adjust the parameters as necessary but this will get you moving in the right direction and will cause the container to create NonShared versions of any part that is marked as Any (which is the default).
Well, CreationPolicy is passed as part of a component's metadata. This means, you should be able to query the metadata for the part, and see if it exists. The way CreationPolicy is specified in metadata is to use the full type name System.ComponentModel.Composition.CreationPolicy as the key, and the enum result as the value. So, knowing this we can build an extension method:
public static T GetExportedValueOrDefault<T>(this CompositionContainer container, CreationPolicy creationPolicy)
{
var metadataKey = typeof(CreationPolicy).FullName;
var lazy = container.GetExportedValueOrDefault<T, IDictionary<string, object>>();
if (lazy == null)
return default(T);
if (lazy.Metadata.ContainsKey(metadataKey))
{
// If the creation policy matches the required, return.
if (((CreationPolicy)lazy.Metadata[metadataKey]) == creationPolicy)
return lazy.Value;
}
else
{
// Return the value as we assume it satisfies the default CreationPolicy = Any
return lazy.Value;
}
return default(T);
}
Now, firstly we create our expected key, and then we grab a Lazy<T, TMetadata> instance which includes the type and any associated metadata as a Lazy<T, IDictionary<string, object>> instance. If the lazy comes back as null, we can fail early because there were no matching parts at all.
Next, we can check the metadata dictionary Lazy.Metadata to determine if the metadata exists. If it does, we need to cast and compare against our chosen metadata. If that succeeds, return our part instance.
If that doesn't succeed (e.g., if the part is using the implicit CreationPolicy of Any [i.e., the PartCreationPolicyAttribute is omitted from the export]), we'll assume that the part can be returned, as we can match on the default Any creation policy, so we can match both NonShared and Shared parts.
You should be able to use this in place of the normal GetExportedValueOrDefault<T> call:
T retrievedComponent = container.GetExportedValueOrDefault<T>(CreationPolicy.NonShared);

Grails: How to make everything I create Upper Case?

I am currently using CSS to change everything I write to upperCase when I create an entry, but that is not enough. When I save things, the text shown in the text fields is upper case, but the real value that Grails stores stays in lower case.
I am assuming I'd need to change something in the controller or anything.
Maybe transforming the $fieldValue CSS could work??
Any ideas would help!
Thnks!
You could just write setters for your domain object?
class Domain {
String aField
void setAField( String s ){
aField = s?.toUpperCase()
}
}
I think you are asking how to change values on your domain objects to uppercase. If this is not the case please clarify the question.
You have a bunch of options. I would recommend
1) In a service method, before you save, using String.toUpperCase() to modify the appropriate values on the domain object.
or
2) You can use the underlying Hibernate interceptors by defining a beforeInsert method on your domain object, and doing the toUpperCase there. (see 5.5.1 of the grails documentation)
or
3) You could do this client side. However, if it is a "business requirement" that the values are stored as upper, then I recommend doing the translation server side. It is easier to wrap tests around that code....
Using annotations is cleanest approach
import org.grails.databinding.BindingFormat
class Person {
#BindingFormat('UPPERCASE')
String someUpperCaseString
#BindingFormat('LOWERCASE')
String someLowerCaseString
}
Here is link for it: Grails doc for data binding
You can use Groovy metaprogramming to change the setter for all domain class String-typed properties without actually writing a custom setter for each property.
To do this, add something like the following to the init closure of Bootstrap.groovy
def init = { servletContext ->
for (dc in grailsApplication.domainClasses) {
dc.class.metaClass.setProperty = { String name, value ->
def metaProperty = delegate.class.metaClass.getMetaProperty(name)
if (metaProperty) {
// change the property value to uppercase if it's a String property
if (value && metaProperty.type == String) {
value = value.toUpperCase()
}
metaProperty.setProperty(delegate, value)
} else {
throw new MissingPropertyException(name, delegate.class)
}
}
}
}

Resources