I am trying to parse expressions such as a*(4+5) in my parser to build the abstract syntax tree.
void addSub() : {}
{
mulDiv() ((<ADD> mulDiv() )| (<SUB> mulDiv() ) )*
}
void mulDiv() : {}
{
factor() ((<MUL> factor() )|( <DIV> factor() ))*
}
void factor() : {}
{
(numeralLit() | booleanLit() | LOOKAHEAD(2) functionCallExp() | idUse())
//TODO add () support
}
however, if I add an expression such as
void parantheses() :{}
{
<LPAR>
addSub()
<RPAR>
}
and place it in factor(), I get an error saying a recursion as occured (parantheses uses addSub()). How would I go about the structure so that it could prevent recursion?
Related
Concisely put into Rust code, I'm trying to generate a pattern match like this:
if let Foo::Variant(_) = value {}
// ^^^^^^^^^^^^^^^
in a macro, with both Foo (a type) and Variant (an identifier) passed to the macro as metavariables. In the real use case, I'm generating a match instead of an if let and am using multiple variants of the same enum, but if let resulted in a shorter reproducible example.
This works with simple enums:
enum Foo {
Variant,
}
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
if let <$enum>::$variant = $value {}
};
}
fn main() {
let foo = Foo::Variant;
match_enum!(foo: <Foo>::Variant);
}
This compiles.
However, when I make the enum variant tuple-like, it breaks (changes highlighted):
enum Foo {
Variant(usize),
// ^^^^^^^
}
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
if let <$enum>::$variant(_) = $value {}
// ^^^
};
}
fn main() {
let foo = Foo::Variant(0);
// ^^^
match_enum!(foo: <Foo>::Variant);
}
| if let <$enum>::$variant(_) = $value {}
| -----------------^^^ unexpected `(` after qualified path
| |
| the qualified path
...
| match_enum!(foo: <Foo>::Variant);
| --------------------------------- in this macro invocation
I have tried some variations, more or less blindly; $enum::$variant(_), <$enum::$variant>(_), <$enum::$variant>::(_) among them.
Is this possible? Am I perhaps using the wrong types of metavariables?
This question seems to be related, but it focuses on mixing unit and tuple variants, and has not been resolved.
The problem seems to be caused by the $enum metavariable, as the following slight modifications show:
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
// does not fix the problem
if let <$enum>::Variant(_) = $value {}
// fixes the problem
if let Bar::$variant(_) = $value {}
};
}
As the problem happens on the syntax level, we can try change the syntactic makeup of the generated code, in particular by introducing a type alias. We then need to scope that type to not leak out of the macro:
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
{
type Enum = $enum;
if let Enum::Variant(_) = $value {}
}
};
}
It's just a workaround, but it's clean enough.
I can't get rid of an error on this code:
#[derive(PartialEq, Copy, Clone)]
pub enum OperationMode {
ECB,
CBC { iv: [u8; 16] },
}
pub struct AES {
key: Vec<u8>,
nr: u8,
mode: OperationMode,
}
impl AES {
pub fn decrypt(&mut self, input: &Vec<u8>) {
match self.mode {
OperationMode::ECB => {},
OperationMode::CBC(_) => {},
};
}
}
The pattern matching at the end of the decrypt function gives an error:
error[E0532]: expected tuple struct/variant, found struct variant `OperationMode::CBC`
--> src/main.rs:17:13
|
17 | OperationMode::CBC(_) => {},
| ^^^^^^^^^^^^^^^^^^ did you mean `OperationMode::CBC { /* fields */ }`?
It tells me to look at the output of rustc --explain E0532 for help, which I did.
They show this example of wrong code:
enum State {
Succeeded,
Failed(String),
}
fn print_on_failure(state: &State) {
match *state {
// error: expected unit struct/variant or constant, found tuple
// variant `State::Failed`
State::Failed => println!("Failed"),
_ => ()
}
}
In this example, the error occurs because State::Failed has a field which isn't matched. It should be State::Failed(ref msg).
In my case I'm matching the field of my enum because I'm doing OperationMode::CBC(_). Why does the error happen?
Enum variants have three possible syntaxes:
unit
enum A { One }
tuple
enum B { Two(u8, bool) }
struct
enum C { Three { a: f64, b: String } }
You have to use the same syntax when pattern matching as the syntax the variant was defined as:
unit
match something {
A::One => { /* Do something */ }
}
tuple
match something {
B::Two(x, y) => { /* Do something */ }
}
struct
match something {
C::Three { a: another_name, b } => { /* Do something */ }
}
Beyond that, you can use various patterns that allow ignoring a value, such as _ or ... In this case, you need curly braces and the .. catch-all:
OperationMode::CBC { .. } => { /* Do something */ }
See also:
Ignoring Values in a Pattern in The Rust Programming Language
Appendix B: Operators and Symbols in The Rust Programming Language
How to match struct fields in Rust?
I want to avoid creating a switch case and instead use an enum but when writing the following code, I get a compile error saying unexpected token public:
public enum Status {
INACTIVE {
public void doSomething() {
//do something
}
},
ACTIVE {
public void doSomething() {
//do something else
}
},
UNKNOWN {
public void doSomething() {
//do something totally different
}
};
public abstract void doSomething()
}
Basically what I want to achieve is something similar to this:
public enum Status {
ACTIVE,
INACTIVE,
UNKNOWN;
}
switch (getState()) {
case INACTIVE:
//do something
break;
case ACTIVE:
//do something else
break;
case UNKNOWN:
//do something totally different
break;
}
Is this allowed in Gosu? How should I go about achieving such a behavior?
You have miss-understood the concept of Enum. First of all, enum is inherited from java.lang.Enum. It's not allowed to implement inner classes to Enum constants. You have to consider ACTIVE,INACTIVE and UNKNOWN (Enum constants) as objects of class type Status.
Proof:
Status.ACTIVE.getClass() == class Status
Status.ACTIVE instanceof Status == true
Status.ACTIVE instanceof java.lang.Enum == true
If you want to avoid the switch statement in your main code, you can move the switch into the implementation of enum as follows; (coded in Gosu)
enum Status {
ACTIVE,INACTIVE,UNKNOWN;
public function doSomething(){
switch (this) {
case INACTIVE:
//do something
break;
case ACTIVE:
//do something
break;
case UNKNOWN:
//do something
break;
}
}
}
Now you have the capability to call the doSomething() method from the enum constants in your main code
Example:
var a=Status.ACTIVE
var b=Status.INACTIVE
var c=Status.UNKNOWN
a.doSomething()
b.doSomething()
c.doSomething()
As you can read in
Gosu grammar or below function is not allowed inside enum consts, even brackets {} after consts are not allowed.
What is allowed in enum body:
enumBody = "{" [enumConstants] classMembers "}" .
enumConstants = enumConstant {"," enumConstant} [","] [";"] .
enumConstant = {annotation} id optionalArguments .
So basically in GOSU enum contains consts and rest normally as in any other class.
There are a number of other questions floating around with various complicated answers for this question, but as far as I can see, none of them answer the basic question being posed:
How do you write a factory function that takes a type and returns an instance when the return type is known?
That is:
func factory<T>(T) -> Fooish { ... }
// Usage:
class Something : Fooish { ... }
let x:Fooish = factory(Something)
For example, this code:
public class Fooish {
var x:String = ""
public func foo() -> String {
return x
}
}
public class FooA : Fooish {
public override init() {
super.init()
x = "Hello"
}
}
public class FooB : Fooish {
public override init() {
super.init()
x = "World"
}
}
// This works
print(FooA().foo())
print(FooB().foo())
// This does not work
func factory<U>(type:U) -> Fooish {
return U()
}
print(factory(FooA).foo())
print(factory(FooB).foo())
Results in this error:
Sources/main.swift:32:10: error: 'U' cannot be constructed because it has no accessible initializers
return U()
^
<unknown>:0: error: build had 1 command failures
So what is the bound to place on T, such that we can call T() and know that the returned instance is a some Fooish?
Some answers suggest using a protocol for it, such as:
protocol IsFoo {
init()
}
factory<T: IsFoo>(t:T) -> Fooish { .. }
However, this doesn't seem to work:
error: cannot invoke 'factory' with an argument list of type '((FooA).Type)'
expected an argument list of type '(U)'
Every answer to this question seems to have multiple conflicting and updated answers; please, just simply post the snippet above, with a working implementation of the function factory, for swift 2.2.
Make a protocol which defines a common initializer to be called by the factory method:
protocol FactoryInitializable {
init ()
}
func factory<T: FactoryInitializable>(type: T.Type) -> T {
return T()
}
public class Fooish {
var x = ""
public func foo() -> String {
return x
}
}
public class FooA : Fooish, FactoryInitializable {
required public override init() {
super.init()
x = "This is FooA"
}
}
public class FooB : Fooish, FactoryInitializable {
required public override init() {
super.init()
x = "This is FooB"
}
}
let a = factory(FooA)
let b = factory(FooB)
print(a.x) // print: This is FooA
print(b.x) // print: This is FooB
How to do something similar to this D and Java code in Rust?
Java:
import java.nio.file.*;
import java.io.*;
public class Main {
public static void main( String[] args ) throws IOException
{
Files.lines(Paths.get("/home/kozak/test.txt"))
.filter(s -> s.endsWith("/bin/bash"))
.map(s -> s.split(":", 2)[0])
.forEach(System.out::println);
}
}
D language:
import std.algorithm;
import std.stdio;
void main() {
File("/home/kozak/test.txt")
.byLine
.filter!((s)=>s.endsWith("/bin/bash"))
.map!((s)=>s.splitter(":").front)
.each!writeln;
}
I try it, but I am lost with all this ownership stuff
my rust code:
use std::io::BufReader;
use std::fs::File;
use std::io::BufRead;
use std::io::Lines;
fn main() {
let file = match File::open("/etc/passwd") {
Ok(file) => file,
Err(..) => panic!("room"),
};
let mut reader = BufReader::new(&file);
for line in reader.lines().filter_map(
|x| if match x { Ok(v) => v.rmatches("/bin/bash").count() > 0, Err(e) => false}
{ match x { Ok(v2) => Some(v2.split(":").next()), Err(e2) => None }} else
{ None })
{
print!("{}", line.unwrap() );
}
}
Here you go:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let f = BufReader::new(File::open("/etc/passwd").unwrap());
let it = f.lines()
.map(|line| line.unwrap())
.filter(|line| line.ends_with("/bin/bash"))
.map(|line| line.split(":").next().unwrap().to_owned());
for p in it {
println!("{}", p);
}
}
This code allocates a separate string for each first splitted part though, but I don't think it is possible to avoid it without streaming iterators. And, of course, error handling here is really lax.
I guess an imperative approach would be more idiomatic, especially in regard to error handling:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let f = BufReader::new(File::open("/etc/passwd").unwrap());
for line in f.lines() {
match line {
Ok(line) => if line.ends_with("/bin/bash") {
if let Some(name) = line.split(":").next() {
println!("{}", name);
} else {
println!("Line does not contain ':'");
}
},
Err(e) => panic!("Error reading file: {}", e)
}
}
}