Skip to content

Commit

Permalink
Unify parse_required
Browse files Browse the repository at this point in the history
  • Loading branch information
rasmusgo committed May 15, 2024
1 parent 85ad329 commit f96c98d
Showing 1 changed file with 107 additions and 182 deletions.
289 changes: 107 additions & 182 deletions generator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl Parser {
match self.reader.next().expect("failed to parse XML") {
StartElement { name, .. } => match &name.local_name[..] {
"require" => {
self.parse_feature_required();
self.parse_required(None, None);
}
_ => {
eprintln!("unimplemented feature element: {}", name.local_name);
Expand All @@ -192,27 +192,112 @@ impl Parser {
}
}

fn parse_feature_required(&mut self) {
fn parse_extensions(&mut self) {
loop {
use XmlEvent::*;
match self.reader.next().expect("failed to parse XML") {
StartElement {
name, attributes, ..
} => match &name.local_name[..] {
"extension" => {
if let StartElement { name, .. } =
self.reader.next().expect("failed to parse XML")
{
if name.local_name == "require" {
self.parse_extension_required(&attributes);
} else {
eprintln!("unexpected extension element: {}", name.local_name);
}
} else {
eprintln!("unexpected extension event");
}
self.finish_element();
}
_ => {
eprintln!("unimplemented extensions element: {}", name.local_name);
self.finish_element();
}
},
EndElement { name } => {
if name.local_name == "extensions" {
break;
}
eprintln!("unexpected end element: {}", name);
}
EndDocument => {
panic!("unexpected end of document");
}
_ => {}
}
}
}

fn parse_extension_required(&mut self, attrs: &[OwnedAttribute]) {
let ext_name = Rc::<str>::from(attr(attrs, "name").unwrap());
let ext_number = attr(attrs, "number").unwrap().parse::<i32>().unwrap();
let (ext_version, commands) = self.parse_required(Some(&ext_name), Some(ext_number));
if attr(attrs, "supported").map_or(false, |x| x == "disabled") {
self.disabled_exts.insert(ext_name);
} else {
let provisional = attr(attrs, "provisional").map_or(false, |x| x == "true");

let (tag_name, _) = split_ext_tag(&ext_name);
let ext = Extension {
name: ext_name.clone(),
version: ext_version.unwrap(),
commands,
};

if let Some(tag) = self.extensions.get_mut(tag_name) {
tag.extensions.push(ext);
} else if provisional {
self.extensions.insert(
tag_name.into(),
Tag {
extensions: vec![ext],
},
);
} else {
eprintln!("ignoring extension with unlisted tag: {}", ext_name);
}
}
}

fn parse_required(
&mut self,
ext_name: Option<&Rc<str>>,
ext_number: Option<i32>,
) -> (Option<u32>, Vec<String>) {
assert_eq!(ext_name.is_some(), ext_number.is_some());
let mut ext_version = None;
let mut commands = Vec::new();
loop {
use XmlEvent::*;
match self.reader.next().expect("failed to parse XML") {
StartElement {
name, attributes, ..
} => match &name.local_name[..] {
"command" => {
let _name = attr(&attributes, "name").unwrap();
let _comment = attr(&attributes, "comment");
let cmd = attr(&attributes, "name").unwrap();
if let Some(ext_name) = ext_name {
if let Some(command) = self.commands.get_mut(cmd) {
command.extension = Some(ext_name.clone());
}
}
commands.push(cmd.into());
self.finish_element();
}
"enum" => {
let name = attr(&attributes, "name").unwrap();
if let Some(extends) = attr(&attributes, "extends") {
const EXT_BASE: i32 = 1_000_000_000;
const EXT_BLOCK_SIZE: i32 = 1000;
let ext_number = attr(&attributes, "extnumber")
.unwrap()
.parse::<i32>()
.unwrap();
let ext_number = ext_number.unwrap_or_else(|| {
attr(&attributes, "extnumber")
.unwrap()
.parse::<i32>()
.unwrap()
});

let value = if let Some(offset) = attr(&attributes, "offset") {
let offset = offset.parse::<i32>().unwrap();
Expand Down Expand Up @@ -256,170 +341,34 @@ impl Parser {
}
} else if let Some(alias) = attr(&attributes, "alias") {
self.api_aliases.push((name.into(), alias.into()));
} else if name.ends_with("SPEC_VERSION") {
let value = attr(&attributes, "value").unwrap();
ext_version = Some(value.parse().unwrap());
} else if name.ends_with("EXTENSION_NAME") {
let value = attr(&attributes, "value").unwrap();
assert_eq!(&ext_name.unwrap()[..], &value[1..value.len() - 1]);
} else if let Some(value) = attr(&attributes, "value") {
self.api_constants
.push((name.into(), value.parse().unwrap()));
}
self.finish_element();
}
"type" => {
self.parse_type(&attributes);
}
_ => {
eprintln!("unimplemented feature require element: {}", name.local_name);
self.finish_element();
}
},
EndElement { name } => {
if name.local_name == "require" {
break;
}
eprintln!("unexpected end element: {}", name);
}
EndDocument => {
panic!("unexpected end of document");
}
_ => {}
}
}
}

fn parse_extensions(&mut self) {
loop {
use XmlEvent::*;
match self.reader.next().expect("failed to parse XML") {
StartElement {
name, attributes, ..
} => match &name.local_name[..] {
"extension" => {
if let StartElement { name, .. } =
self.reader.next().expect("failed to parse XML")
{
if name.local_name == "require" {
self.parse_extension_required(&attributes);
} else {
eprintln!("unexpected extension element: {}", name.local_name);
if let Some(ext_name) = ext_name {
let ty = attr(&attributes, "name").unwrap();
if let Some(s) = self.structs.get_mut(ty) {
s.extension = Some(ext_name.clone());
}
self.finish_element();
} else {
eprintln!("unexpected extension event");
self.parse_type(&attributes);
}
self.finish_element();
}
_ => {
eprintln!("unimplemented extensions element: {}", name.local_name);
eprintln!("unimplemented require element: {}", name.local_name);
self.finish_element();
}
},
EndElement { name } => {
if name.local_name == "extensions" {
break;
}
eprintln!("unexpected end element: {}", name);
}
EndDocument => {
panic!("unexpected end of document");
}
_ => {}
}
}
}

fn parse_extension_required(&mut self, attrs: &[OwnedAttribute]) {
let ext_name = Rc::<str>::from(attr(attrs, "name").unwrap());
let ext_number = attr(attrs, "number").unwrap().parse::<i32>().unwrap();
let mut ext_version = None;
let mut commands = Vec::new();
loop {
use XmlEvent::*;
match self.reader.next().expect("failed to parse XML") {
StartElement {
name, attributes, ..
} => {
match &name.local_name[..] {
"command" => {
let cmd = attr(&attributes, "name").unwrap();
if let Some(command) = self.commands.get_mut(cmd) {
command.extension = Some(ext_name.clone());
}
commands.push(cmd.into());
}
"enum" => {
let name = attr(&attributes, "name").unwrap();
if let Some(extends) = attr(&attributes, "extends") {
const EXT_BASE: i32 = 1_000_000_000;
const EXT_BLOCK_SIZE: i32 = 1000;

let value = if let Some(offset) = attr(&attributes, "offset") {
let offset = offset.parse::<i32>().unwrap();
let sign =
if attr(&attributes, "dir").map_or(false, |x| x == "-") {
-1
} else {
1
};
ConstantValue::Literal(
sign * (EXT_BASE
+ (ext_number - 1) * EXT_BLOCK_SIZE
+ offset),
)
} else if let Some(bitpos) = attr(&attributes, "bitpos") {
ConstantValue::Literal(bitpos.parse::<i32>().unwrap())
} else {
ConstantValue::Alias(attr(&attributes, "alias").unwrap().into())
};
let bitmasks = &mut self.bitmasks;
if let Some(e) = self.enums.get_mut(extends) {
e.values.push(Constant {
name: name.into(),
value,
comment: attr(&attributes, "comment")
.and_then(tidy_comment),
});
} else if let Some(e) = self
.bitvalues
.get(extends)
.and_then(|x| bitmasks.get_mut(x))
{
e.values.push(Constant {
name: name.into(),
value: match value {
ConstantValue::Literal(x) => {
ConstantValue::Literal(x as u64)
}
ConstantValue::Alias(x) => ConstantValue::Alias(x),
},
comment: attr(&attributes, "comment")
.and_then(tidy_comment),
});
} else {
eprintln!("extension to unrecognized type {}", extends);
}
} else if let Some(alias) = attr(&attributes, "alias") {
self.api_aliases.push((name.into(), alias.into()));
} else if name.ends_with("SPEC_VERSION") {
let value = attr(&attributes, "value").unwrap();
ext_version = Some(value.parse().unwrap());
} else if name.ends_with("EXTENSION_NAME") {
let value = attr(&attributes, "value").unwrap();
assert_eq!(&ext_name[..], &value[1..value.len() - 1]);
} else {
let value = attr(&attributes, "value").unwrap();
self.api_constants
.push((name.into(), value.parse().unwrap()));
}
}
"type" => {
let ty = attr(&attributes, "name").unwrap();
if let Some(s) = self.structs.get_mut(ty) {
s.extension = Some(ext_name.clone());
}
}
_ => {
eprintln!("unimplemented extension element: {}", name.local_name);
}
}
self.finish_element();
}
EndElement { name } => {
if name.local_name == "require" {
break;
Expand All @@ -432,31 +381,7 @@ impl Parser {
_ => {}
}
}
if attr(attrs, "supported").map_or(false, |x| x == "disabled") {
self.disabled_exts.insert(ext_name);
} else {
let provisional = attr(attrs, "provisional").map_or(false, |x| x == "true");

let (tag_name, _) = split_ext_tag(&ext_name);
let ext = Extension {
name: ext_name.clone(),
version: ext_version.unwrap(),
commands,
};

if let Some(tag) = self.extensions.get_mut(tag_name) {
tag.extensions.push(ext);
} else if provisional {
self.extensions.insert(
tag_name.into(),
Tag {
extensions: vec![ext],
},
);
} else {
eprintln!("ignoring extension with unlisted tag: {}", ext_name);
}
}
(ext_version, commands)
}

fn parse_commands(&mut self) {
Expand Down

0 comments on commit f96c98d

Please sign in to comment.